Spring AOP 具体应用就是面向切面编程。AOP就是在我们原先的目标类上面进行一定程度的封装,在方法执行前、方法执行后、方法抛出异常,方法返回后调用某个方法。Spring AOP是基于动态代理实现的,默认使用JDK动态代理(可以强制使用CGLIB代理)。
基本概念
切面(Aspect):切面是指将切点和通知模块化,通常用@Aspect注解来标注切面
连接点(Join point):在程序执行过程中某个特定的点,例如某个方法调用的时间点或者处理异常的时间点。在Spring AOP中,一个连接点总是代表一个方法的执行
通知(Advice):在某个连接点上执行的方法,通常有前置通知,后置通知,环绕通知,异常通知等等。
切点(Pointcut):匹配连接点的断言。通知和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的方法时)。切点表达式如何和连接点匹配是AOP的核心:Spring默认使用AspectJ切点语义
引入(Introduction):声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被通知的对象上。例如,可以使用引入来使bean实现 IsModified接口, 以便简化缓存机制(在AspectJ社区,引入也被称为内部类型声明(inter))
目标对象(Target object):被一个或者多个切面所通知的对象。也被称作被通知(advised)对象。既然Spring AOP是通过运行时代理实现的,那么这个对象永远是一个被代理(proxied)的对象。
AOP代理(AOP proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
织入(Weaving): 把切面连接到其它的应用程序类型或者对象上,并创建一个被被通知的对象的过程。这个过程可以在编译时(例如使用AspectJ编译器)、类加载时或运行时中完成。 Spring和其他纯Java AOP框架一样,是在运行时完成织入的。
通知类型:
前置通知(Before advice): 在连接点之前运行但无法阻止执行流程进入连接点的通知(除非它引发异常)
后置返回通知(After returning advice):在连接点正常完成后执行的通知(例如,当方法没有抛出任何异常并正常返回时)
后置异常通知(After throwing advice): 在方法抛出异常退出时执行的通知
后置通知(总会执行)(After (finally) advice): 当连接点退出的时候执行的通知(无论是正常返回还是异常退出)
环绕通知(Around Advice):环绕连接点的通知,例如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为。它可以选择是否继续执行连接点或直接返回自定义的返回值又或抛出异常将执行结束
spring aop源码解析
Spring基本使用很简单,不需要多说,这里简单贴个demo
@Aspect
@Order
@Component
public class LogAspect {
@Pointcut("execution(* com.dm.Calculate.*(..))")
public void pointCut(){};
@Before(value = "pointCut()")
public void methodBefore(JoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行目标方法【"+methodName+"】的<前置通知>,入参"+ Arrays.asList(joinPoint.getArgs()));
}
@After(value = "pointCut()")
public void methodAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行目标方法【"+methodName+"】的<后置通知>,入参"+Arrays.asList(joinPoint.getArgs()));
}
@AfterReturning(value = "pointCut()",returning = "result")
public void methodReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行目标方法【"+methodName+"】的<返回通知>,入参"+Arrays.asList(joinPoint.getArgs()));
}
@AfterThrowing(value = "pointCut()")
public void methodAfterThrowing(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行目标方法【"+methodName+"】的<异常通知>,入参"+Arrays.asList(joinPoint.getArgs()));
}
}
使用AOP配置类需要配置@EnableAspectJAutoProxy这个注解
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.dm")
public class MainConfig {
}
我们从@EnableAspectJAutoProxy这个注解入手,到@Import(AspectJAutoProxyRegistrar.class)
然后通过父类的registerBeanDefinitions方法注册Bean定义,分析registerBeanDefinitions方法发现注册了AnnotationAwareAspectJAutoProxyCreator这个类并且解析了注解上配置的属性proxyTargetClass和exposeProxy
现在重点关注AnnotationAwareAspectJAutoProxyCreator这个类

切面解析
发现AnnotationAwareAspectJAutoProxyCreator实现了InstantiationAwareBeanPostProcessor这个类,这个后置处理器在创建Bean之前执行,这里AOP重写这个postProcessBeforeInstantiation方法实现了AOP 切面的解析。
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
//构建我们的缓存key,下次调用不会重新解析bean
Object cacheKey = getCacheKey(beanClass, beanName);
//没有beanName或者没有包含在targetSourcedBeans中(一般都不会包含,因为targetSource需要手动设置,一般情况不会设置)
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
//被解析过直接返回
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//判断是不是基础的bean(是不是切面类、通知、切点等)
//判断是不是应该跳过 默认false(切面解析也在其中)
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
/**
* TargetSource代理逻辑的实现,在创建代理时默认是SingletonTargetSource
* 所以如果指定了TargetSource 说明有自己的代理逻辑实现,在这就直接创建代理
*/
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
@Override
protected boolean isInfrastructureClass(Class<?> beanClass) {
// 除了是切面相关的基础的bean(Advice,Pointcut,Advisor,AopInfrastructureBean) 还判断了是不是切面
return (super.isInfrastructureClass(beanClass) ||
(this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 找到候选的Advisors(通知 前置通知、后置通知等..)
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
findCandidateAdvisors->findAdvisorBeans
@Override
protected List<Advisor> findCandidateAdvisors() {
// 找实现了Advisors接口的实现类,我们用的是注解方式,这里返回是空,其实这里还跟事务有关,暂时不做了解
List<Advisor> advisors = super.findCandidateAdvisors();
//找出Aspect相关的信息之后封装为一个advisor
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
//返回我们所有的通知
return advisors;
}
aspectJAdvisorsBuilder.buildAspectJAdvisors方法
public List<Advisor> buildAspectJAdvisors() {
// 用于保存切面的名称,该地方aspectNames 是我们的类级别的缓存,用户缓存已经解析出来的切面信息
List<String> aspectNames = this.aspectBeanNames;
// 缓存字段aspectNames没有值 会在第一个单例执行后置处理器(AnnotationAwareAspectJAutoProxyCreator注册之后)的时候就会触发解析切面的操作
if (aspectNames == null) {
// 加上同步锁, 防止多线程同时加载Aspect
synchronized (this) {
aspectNames = this.aspectBeanNames;
//做了双重检查加锁
if (aspectNames == null) {
// 保存所有通知的集合
List<Advisor> advisors = new ArrayList<>();
// 保存切面的名称的集合
aspectNames = new ArrayList<>();
//aop去容器中获取到所有的组件的名称,然后再经过遍历,这个过程是十分的消耗性能的
//所以spring再这里加入了保存切面信息的缓存
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
//遍历我们从IOC容器中获取处的所有bean的名称
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
//通过beanName去容器中获取到对应class对象
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//根据class对象判断是不是切面
if (this.advisorFactory.isAspect(beanType)) {
//是切面类,加入到缓存中
aspectNames.add(beanName);
//把beanName和class对象构建成为一个AspectMetadata
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//构建切面注解的实例工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//获取我们的通知对象
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
//加入到缓存中
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
//真正的创建切面的时候,我们不需要去解析了而是直接去缓存中获取处
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
创建代理
创建代理准备来说有2个地方
- 正常来说都是初始化之后调用后置处理器
BeanPostProcessors.postProcessAfterInitialization方法创建代理 - 循环依赖的时候,在getSingleton方法中调用三级缓存中钩子方法创建早期对象创建代理,是后置处理器
SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference方法
我们看正常调用AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization方法
AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization方法
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
//获取缓存key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 之前循环依赖创建的动态代理 如果是现在的bean 就不再创建,,并且移除
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 该方法将会返回动态代理实例
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary()方法
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//已经被处理过(解析切面时targetSourcedBeans出现过) 就是自己实现创建动态代理逻辑
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
//不需要增强的
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//之前解析切面的时候判断过了(防止bean被修改出现切面不一致)
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 根据当前bean找到匹配的advisor --重点方法--
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 当前bean匹配到了advisor
if (specificInterceptors != DO_NOT_PROXY) {
// 标记为已处理
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建我们的真正的代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
//加入到缓存
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
getAdvicesAndAdvisorsForBean方法
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
//找到和当前bean匹配的advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
//如果没找到,不创建代理
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//拿到接口方式的AOP
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//判断我们的通知能不能作用到当前的类上(切点是否命中当前Bean)
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
//对我们的advisor进行排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply这里面做的事情主要是调用Aspectj的2次筛选,看Advisor是否命中class。
下面就是Aspectj看是否命中class的代码
findAdvisorsThatCanApply-> AopUtils.findAdvisorsThatCanApply->canApply->canApply->canApply
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 第一次过滤,进行类级别过滤(通过AspectJ)
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 进行方法级别过滤
//如果pc.getMethodMatcher()返回TrueMethodMatcher则匹配所有方法
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
//判断匹配器是不是IntroductionAwareMethodMatcher 只有AspectJExpressionPointCut才会实现这个接口
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
//创建一个集合用于保存targetClass 的class对象
Set<Class<?>> classes = new LinkedHashSet<>();
//判断当前class是不是代理的class对象
if (!Proxy.isProxyClass(targetClass)) {
//加入到集合中去
classes.add(ClassUtils.getUserClass(targetClass));
}
//获取到targetClass所实现的接口的class对象,然后加入到集合中
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//循环所有的class对象
for (Class<?> clazz : classes) {
//通过class获取到所有的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
//循环我们的方法
for (Method method : methods) {
//第二次过滤,通过methodMatcher.matches来匹配我们的方法
if (introductionAwareMethodMatcher != null ?
// 通过切点表达式进行匹配 AspectJ方式
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
// 通过方法匹配器进行匹配 内置aop接口方式
methodMatcher.matches(method, targetClass)) {
// 只要有1个方法匹配上了就创建代理
return true;
}
}
}
return false;
}
createProxy方法
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建一个代理对象工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//为proxyFactory设置创建jdk代理还是cglib代理
//如果设置了 <aop:aspectj-autoproxy proxy-target-class="true"/>或者配置上加@EnableAspectJAutoProxy(proxyTargetClass = true),说明强制使用cglib
if (!proxyFactory.isProxyTargetClass()) {
// 内部设置的,配置类就会设置这个属性
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 检查有没有接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//把我们的specificInterceptors数组中的Advisor转化为数组形式的
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//为我们的代理工厂加入通知器,
proxyFactory.addAdvisors(advisors);
//设置targetSource对象
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// 代表之前是否筛选advise.
// 因为继承了AbstractAdvisorAutoProxyCreator,并且之前调用了findEligibleAdvisors进行筛选, 所以是true
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//真正的创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
代理方式的选用
proxyFactory.getProxy方法->createAopProxy方法-> getAopProxyFactory().createAopProxy()
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//判断我们是否前置指定使用cglib代理ProxyTargetClass=true
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//targetClass是接口,使用的就是jdk代理,一般不走
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
//动态代理
return new JdkDynamicAopProxy(config);
}
}
从这也可以看出,springAOP 默认就是JDK动态代理,除非指定proxyTargetClass=true才会是Cglib代理
代理调用
从JDK动态代理入手JdkDynamicAopProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
//获取到我们的目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//若执行代理对象的equals方法不需要代理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
//若执行的是hashCode方法不需要代理
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
//若执行的class对象是DecoratingProxy则不会对其应用切面进行方法的增强,返回源目标类型
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 如果目标对象实现的Advised接口,则不会对其应用切面进行方法的增强,直接执行方法
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//【暴露我们的代理对象到线程变量中】需要搭配@EnableAspectJAutoProxy(exposeProxy = true)
if (this.advised.exposeProxy) {
//把我们的代理对象暴露到线程变量中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//获取我们的目标对象
target = targetSource.getTarget();
//获取我们目标对象的class
Class<?> targetClass = (target != null ? target.getClass() : null);
//把我们的aop的advisor全部转化为拦截器,通过责任链模式调用(责任链调用需要类型一致,所以这里需要转化)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//如果我们的拦截器链为空
if (chain.isEmpty()) {
//通过反射直接调用执行
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//创建一个方法调用对象
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//调用执行
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
责任链调用
public Object proceed() throws Throwable {
//从-1开始,结束条件执行目标方法是下标=拦截器的长度-1(执行到了最后一个拦截器的时候)
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//获取第一个方法拦截器使用的是前++
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
//在这个地方需要注意,抵用第一个拦截器的invoke方法,传入的是this当前的方法拦截器对象
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
流程图
