四.Sping之AOP源码

本文解读AOP是如何增强方法功能的。

需要提前了解@Import 注解的功能:https://blog.csdn.net/u014203449/article/details/86559350

BeanPostProcessor 后置处理器的功能:https://blog.csdn.net/u014203449/article/details/86665963

Aware接口:https://blog.csdn.net/u014203449/article/details/105414733

一.演示案列

1、导入aop模块;Spring AOP:(spring-aspects)

      <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>4.3.12.RELEASE</version>
		</dependency>
      <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.12.RELEASE</version>
		</dependency>

 2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)

public class MathCalculator {
	
	public int div(int i,int j){
		System.out.println("MathCalculator...div...");
		return i/j;	
	}

}

  3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
          通知方法:
              前置通知(@Before):logStart:在目标方法(div)运行之前运行
              后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
              返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
              异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
              环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())

  4、给切面类的目标方法标注何时何地运行(通知注解);
  5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
  6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)

  7、标明切点,切点可以是某包、某类、某方法、某注解,通知注解的value值为切点

/**
 * 切面类
 * @author lfy
 * 
 * @Aspect: 告诉Spring当前类是一个切面类
 *
 */
@Aspect
public class LogAspects {
	
	//抽取公共的切入点表达式
	//1、本类引用
	//2、其他的切面引用
	@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
	public void pointCut(){};
	
	//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
	@Before("pointCut()")
	public void logStart(JoinPoint joinPoint){
		Object[] args = joinPoint.getArgs();
		System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
	}
	
	@After("com.atguigu.aop.LogAspects.pointCut()")
	public void logEnd(JoinPoint joinPoint){
		System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
	}
	
	//JoinPoint一定要出现在参数表的第一位
	@AfterReturning(value="pointCut()",returning="result")
	public void logReturn(JoinPoint joinPoint,Object result){
		System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
	}
	
	@AfterThrowing(value="pointCut()",throwing="exception")
	public void logException(JoinPoint joinPoint,Exception exception){
		System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
	}

}

 8、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
          在Spring中很多的 @EnableXXX;

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
	 
	//业务逻辑类加入容器中
	@Bean
	public MathCalculator calculator(){
		return new MathCalculator();
	}

	//切面类加入到容器中
	@Bean
	public LogAspects logAspects(){
		return new LogAspects();
	}
}

单元测试:

	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
		MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
		mathCalculator.div(1, 0);
		applicationContext.close();
	}

二.@EnableAspectJAutoProxy

@EnableAspectJAutoProxy注解启动了AOP功能,Spring中很多注解都是EnableXXX 去启动某个功能,我们先来看这个注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   
   

@EnableAspectJAutoProxy 上有@Import注解,它会向容器中注入参数类的实例,点击看参数 AspectJAutoProxyRegistrar 类。

@Import注解有三种用法,我这篇文章介绍过:https://blog.csdn.net/u014203449/article/details/86559350

/**
 * Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
 * AnnotationAwareAspectJAutoProxyCreator} against the current {@link BeanDefinitionRegistry}
 * as appropriate based on a given @{@link EnableAspectJAutoProxy} annotation.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 * @see EnableAspectJAutoProxy
 */
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
	 * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
	 * {@code @Configuration} class.
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}

}

可以看到类注释说 基于 EnableAspectJAutoProxy注解,将 AnnotationAwareAspectJAutoProxyCreator 用BeanDefinitionRegistry注册。

AspectJAutoProxyRegistrar 类实现 ImportBeanDefinitionRegistrar 接口,在registerBeanDefinitions方法可以用参数BeanDefinitionRegistry 去手动注册实例到容器中。

可以看到  AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 这行代码方法名 注册AspectJxxx 如果需要的话。

点进去看。

	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
		return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
	}
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

注意上面这个方法的参数是AnnotationAwareAspectJAutoProxyCreator.Class. 再点进去。

	public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";	

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

这个方法对参数class判断registry中是否有这个BeanDefinition,如果没有就new一个并且register这个BeanDefiniton到registry,如果有则比较优先级,更换beanClassName.

AnnotationAwareAspectJAutoProxyCreator类对应的BeanDefinition名字是固定的org.springframework.aop.config.internalAutoProxyCreator,根据这个名字取判断是否存在。

打断点看看是如何判断registry 是否有这个BeanDefinition。

来到了 DefaultListableBeanFactory类,看到用一些集合存储了已注册的BeanDefinition。

打断点,容器第一次启动时还没有这个BeanDefinition,所以会新创建我们的AnnotationAwareAspectJAutoProxyCreator对应的BeanDefinition.

断点进入 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);又来到了DefaultListableBeanFactory类。

简单看看就是把BeanDefinition用集合变量存下来。 

再看看BeanDinition有哪些东西,截取一部分代码:看方法名大概明白什么意思,BeanDinition 可以设置和获取实例在Spring容器中的属性如是否单例、优先级、对应的Class、懒加载、依赖哪些其他组件(这个蛮有用,容器在创建此实例前优先创建它依赖的实例)

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	String getParentName();

	void setBeanClassName(String beanClassName);

	String getBeanClassName();

	void setScope(String scope);

	String getScope();

	void setLazyInit(boolean lazyInit);

	boolean isLazyInit();

	void setDependsOn(String... dependsOn);

	String[] getDependsOn();

	void setAutowireCandidate(boolean autowireCandidate);

	boolean isAutowireCandidate();

	void setPrimary(boolean primary);

	boolean isPrimary();

回到 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry),以上逻辑说明了@EnableAspectJAutoProxy 会将 AnnotationAwareAspectJAutoProxyCreator.Class 做参数创建一个BeanDefinition并保存到DefaultListableBeanFactory。

三.AnnotationAwareAspectJAutoProxyCreator的创建、初始化

来看看AnnotationAwareAspectJAutoProxyCreator是如何发挥作用的。

后面的类层层继承,就不一一截图了,把继承的关系链写下来:

AnnotationAwareAspectJAutoProxyCreator:
          AnnotationAwareAspectJAutoProxyCreator
              ->AspectJAwareAdvisorAutoProxyCreator
                  ->AbstractAdvisorAutoProxyCreator
                      ->AbstractAutoProxyCreator
                              implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(关键)

SmartInstantiationAwareBeanPostProcessor接口

       ->InstantiationAwareBeanPostProcessor

             ->BeanPostProcessor

BeanPostProcessor 是后置处理器,在实例初始化前后可以对实例进行操作。

看看InstantiationAwareBeanPostProcessor : 看文档注释可以明白,下面两个方法可以在实例创建前后进行处理。postProcessBeforeInstantiation方法注释:返回的object可以是目标bean的代理对象。

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

 /**Apply this BeanPostProcessor <i>before the target bean gets instantiated</i>.
	 * The returned bean object may be a proxy to use instead of the target bean,
	 * effectively suppressing default instantiation of the target bean.**/
	Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;


	boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
}

回到AbstractAutoProxyCreator类,它实现了后置处理器接口 这样它会成为一个后置处理器; 实现了BeanFactoryAware接口,会将Spring的工厂组件注入其中。

关于XXXAware接口:https://blog.csdn.net/u014203449/article/details/105414733

以上说明AnnotationAwareAspectJAutoProxyCreator 本质是个后置处理器BeanProcessor,且其注入了BeanFachory。

我们先把断点打到AnnotationAwareAspectJAutoProxyCreator 和其层层父类的 setBeanFactory 方法上,这样可以看到它是怎样把BeanFactory注入进去,即何时执行的实例初始化方法。

AbstractAdvisorAutoProxyCreator 和AbstractAutoProxyCreator 都有setBeanFactory方法,其中调用了 initBeanFactory().

断点来了:

来看看调用链:

test01是我们的单元测试方法,依次往上看方法

第一个是 AnnotationConfigApplicationContext的构造器,这是在单元测试创建容器时调用的:

再往进看,调用到了 refresh的 registerBeanPostProcessors方法,方法名称是注册后置处理器

点击进入 PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);这个方法要仔细看看。

断点到了 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); 从工厂中获得一个BeanPostProcessor,从工厂获得也就是创建实例,这符合我们打断点的目的:在AnnotationAwareAspectJAutoProxyCreator实例创建完成后,执行初始化方法中, 调用setBeanFactory将BeanFactory注入。

先整体看看registerBeanPostProcessors。如下图,第一步先得到所有BeanProcessor的名称。

第二步,添加一个BeanPostProcessor,看注释是这个后置处理器是为了记录日志,在其他后置处理器创建实例时。

第三步,看注释和代码,将BeanPostProcossor 的Name数组 按照实现PriorityOrdered 、Orderd 接口和没实现排序接口的划分成不同的集合,如PriorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors。

将实现了MergedBeanDefinitionPostProcessor接口的分到internalPostProcessors 内部后置处理器集合。

如果实现了PriorityOrdered接口,则直接通过BeanFactory得到实例,并保存到PriorityOrderedPostProcessors集合。

再往后看,就是将PriorityOrderedPostProcessors集合排序sort,然后调用 registerBeanPostProcessors 方法将实例注册到容器。

以及将其他实现ordered接口的 和没有实现排序接口的BeanPostProcessor创建并注册。

看看 registerBeanPostProcessors,如何注册BeanPostProcessor:往BeanFactory中添加

到了 AbstractBeanFactory.addBeanPostProcessor(),注册就是往AbstractBeanFactory类的beanPostProcessors集合中添加一个元素。

回到之前打断点的地方,AnnotationAwareAspectJAutoProxyCreator实现了Ordered接口,所以被分到了OrderedPost集合中。

接下来看看,实例是如何在工厂中创建的。顺着这个线程调用点击,都可以看看,是有关创建实例的过程。

先写下创建实例的简单过程:

                  1)、创建Bean的实例
                  2)、populateBean;给bean的各种属性赋值
                  3)、initializeBean:初始化bean;
                          1)、invokeAwareMethods():处理Aware接口的方法回调,(就是debug的注入工厂)
                          2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
                          3)、invokeInitMethods();执行自定义的初始化方法
                          4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();

断点看到AbstractAutowireCapableBeanFactory.doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args).

看注释:生成实例

设置属性,初始化实例,断点在初始化实例这个方法上。

断点再进去,可以看到断点在 invokeAwareMethods 方法上,即调用Aware方法,看后面分别还有调用前置处理器、ini他、后置处理器等方法,说明前置、后置处理器、Aware方法都是 初始化实例过程的一部分。

进入invokeAwareMethods,根据实例实现了哪些Aware接口,注入对应的组件。

调用线程链再往上,就来到最初我们打断点的地方。

在上面的过程中,看到了AnnotationAwareAspectJAutoProxyCreator是如何创建并初始化的过程,也简单看了实例创建初始化过程。

接下来看看AnnotationAwareAspectJAutoProxyCreator 作为后置处理器BeanPostProcessor是如何发挥作用的。

四.AnnotationAwareAspectJAutoProxyCreator后置处理器功能

把AnnotationAwareAspectJAutoProxyCreator 上有业务逻辑的BeanPostProcessor 方法打上断点,没有逻辑直接返回null或bean的不打断点。来看看AnnotationAwareAspectJAutoProxyCreator 作为BeanPostProcessor是如何发挥作用的。

有两个方法有业务逻辑:

AbstractAutoProxyCreator.postProcessBeforeInstantiation()

AbstractAutoProxyCreator.postProcessAfterInitialization()

从setBeanFactory那放开断点,就来到了 AbstractAutoProxyCreator.postProcessBeforeInstantiation()

从线程调度看,发现依然是refresh方法开始调用的。

看注释,实例化所有剩余的非懒加载的实例。在之前refresh方法中调用了 registerBeanPostProcessors 去实例化并注册了BeanPostProcessor,现在要注册剩余的其他bean。

按照线程调用链,我们点到 preInstantiateSingletons方法。在里面打断点,把断点放行到此处:

可以看到,遍历beanDifinitionNames,判断是否spring工厂中有此bean,没有就getbean()创建bean。

看看目前有多少beanDefinitionNames,之前创建并注册了BeanPostProcessor,现在会实例化剩余的bean,

重点看calculator,这是被AOP增强的类。

把断点放行,让当前beanName 是calculator,看看关注的calculator是如何创建的:

判断spring工厂中没有calculator,所以会执行getBean创建:

断点一路点进去,来到了 AbstractBeanFactory.doGetBean(),这个方法在之前BeanPostProccessor创建时也调用过,方法很长,看注释基本是对bean的校验、先实例化它depends依赖的组件。最后createBean.

再点进去,也是之前BeanPostProccessor创建时见过的方法。不同的是,这次不会直接doCreateBean,

直接跳过 resolveBeforeInstantiation 方法,会发现断点进入了之前设置的 postProcessBeforeInstantiation方法。

回头看看resolveBeforeInstantiation方法,它会先调用BeanPostProcessor的  BeanPostProcessorsBeforeInstantiation方法,尝试直接返回一个Bean,如果返回成功,就执行 BeanPostProcessorsAfterInitialization方法。

这符合 InstantiationAwareBeanPostProcessor 的功能,在实例创建前后执行。

这时能看出AnnotationAwareAspectJAutoProxyCreator作为BeanPostProcessor开始发挥作用了,来看看它的postProcessBeforeInstantiation方法:

里面主要是判断,isInfrastructureClass() 判断当前bean是不是切点、增强器之类。如果是,则加入advisedBeans

判断是否应该跳过,shouldSkip(),里面判断当前bean的名字是不是和 candidateAdvisors 候选增强器的切面相同。如果是也加入

advisedBeans。

可见advisedBeans是用来保存增强器的集合。 结果也是LogAspect加入了advisedBeans,MathCalculator没有加入。

 总结AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】    的作用:
  1)、每一个bean创建之前,调用postProcessBeforeInstantiation();
          关心MathCalculator和LogAspect的创建
          1)、判断当前bean是否在advisedBeans中(保存了所有增强器)
          2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,
              或者是否是切面(@Aspect)
          3)、是否需要跳过shouldSkip()
              1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】
                  每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;
                  判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
              2)、永远返回false

再看AnnotationAwareAspectJAutoProxyCreator 的postProcessAfterInitialization方法,当前bean为calculator时,会进入wrapIfNecessary方法, 包装bean方法。

earlyProxyReferences是创建bean时会把引用加到这个集合,可以自行查看依赖关系。

这是AnnotationAwareAspectJAutoProxyCreator 作为BeanPostProcessor最核心的地方

如果bean是增强器已经在advisedBeans中,或者符合isInfrastructureClass 和shouldSkip 方法,就直接返回bean本身。

否则就会判断增强器数量,如果数量不为空,就认为需要代理、返回一个代理对象。

看看getAdvicesAndAdvisorsForBean方法,找到符合当前bean的增强器。

 1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors
              1、找到 候选的 所有的增强器(找哪些通知方法是需要切入当前bean方法的)  AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean()
              2、获取到能在bean使用的增强器。
              3、给增强器排序      AbstractAdvisorAutoProxyCreator.findEligibleAdvisors

然后创建代理:

  1)、如果当前bean需要增强(有对应的增强器),创建当前bean的代理对象;
              1)、获取所有增强器(通知方法)
              2)、保存到proxyFactory
              3)、创建代理对象:Spring自动决定 ,何时选用何种代理https://www.cnblogs.com/caoxb/p/12406005.html
                  JdkDynamicAopProxy(config);jdk动态代理;
                  ObjenesisCglibAopProxy(config);cglib的动态代理;
   2)、给容器中返回当前组件使用cglib增强了的代理对象;
   3)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;

五.通知方法执行流程

将断点打到切点。

断点进入运行方法,会发现并没有直接进入 div方法,而是进入了 CglibAopProxy的 intercept方法。这就是代理执行的方法

看看方法参数:

method是切点方法,args有参数。

proxy 有增强的信息,当前bean被哪些增强器(通知增强)

方法中会得到一个chain链,比较关键

往进走,缓存不用管,基本都是为了下次使用,第一次肯定没有缓存。进入

this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice

这个方法简单来说是把advisor遍历,转为 MethodInterceptor集合返回

目前有这些advisor增强器,就是切面中的四个通知方法,外加spring默认的ExposeInvocationInterceptor。

MethodInterceptor[] interceptors = registry.getInterceptors(advisor); 这个方法时由advisor变为MethodInterceptor的方法,看看。

判断如果是MethodInterceptor直接强转,如果不是 则通过AdvisorAdapter 适配器转换。

有三个Adapter,遍历尝试转换

转换也就是构造一个MethodInterceptor 方法拦截器

总之最后得到了一个MethodInterceptorChain,由一个默认的ExposeInvocationInterceptor 和四个 我们写的通知组成。

继续CglibAopProxy的 intercept方法。看注释,如果链是空的,则直接调用目标方法。

chain不是空的,则new 一个 CglibMethodInvocation ,并且执行其proceed()方法。

CglibMethodInvocation继承了 ReflectiveMethodInvocation,proceed是ReflectiveMethodInvocation的方法。

CglibMethodInvocation 构造方法没有什么,就是将形参赋值给它的属性。进入proceed方法。interceptorsAndDynamicMethodMatchers是MethodInterceptorChain,第一步是一个判断,如果链当前索引是-1 则跳出。为-1说明链遍历结束了。但现在大小是5。

然后从链中取出第一个拦截器,调用它的invoke方法,形参是CglibMethodInvocation本身(这个MethodInvocation参数保证了一会能继续执行它的proceed方法,然后遍历通知拦截器 执行)。

(其实chain这个名字不太对,这不像一个链,因为前后元素并没有指针关联,是通过共同的形参MethodInvocation,去遍历连接器集合)

断点放开,发现程序又执行到了proceed方法。而这次遍历的是第二个元素,

异常 通知代表的方法拦截器AspectJAfterThrowingAdvice。

断点进入AspectJAfterThrowingAdvice.invoke(),  里面还是调用CglibMethodInvocation(ReflectiveMethodInvocation

)的proceed方法,到时索引将会变为3,执行下一个方法拦截器的proceed方法。

但这里对proceed 捕捉了异常,如果发生异常则调用 增强方法,即异常通知。

到这里已经很明显了,接下来依次调用的拦截器的会是 返回通知、后置通知、被增强的方法、前置通知。

调用后还需要回到原方法,当前置通知执行完,再执行div(被增强的方法),然后后置通知、返回通知,直到第一个默认的方法拦截器执行完。

一次打断点看,接下来是返回通知:执行proceed后,最终会执行返回通知的增强方法。

然后是后置通知,这里用了try finally,保证即使异常也会执行后置通知。

最后是前置通知,先执行前置通知的方法,再执行被增强的方法,

当执行了前置通知后,控制台打印出了前置通知内容:

执行div后,因为有异常,进入了异常方法拦截器的异常捕捉,调用了异常通知,也一样要把异常抛出去。

到这里就说明了通知的执行流程。

六.总结


          1)、  @EnableAspectJAutoProxy 开启AOP功能
          2)、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
          3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
          4)、容器的创建流程:
              1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
              2)、finishBeanFactoryInitialization()初始化剩下的单实例bean
                  1)、创建业务逻辑组件和切面组件
                  2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
                  3)、组件创建完之后,判断组件是否需要增强
                      是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
          5)、执行目标方法:
              1)、代理对象执行目标方法
              2)、CglibAopProxy.intercept();
                  1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
                  2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
                  3)、效果:
                      正常执行:前置通知-》目标方法-》后置通知-》返回通知
                      出现异常:前置通知-》目标方法-》后置通知-》异常通知

猜你喜欢

转载自blog.csdn.net/u014203449/article/details/105707730