【好文转发】浅尝Spring注解开发_AOP原理及完整过程分析(源码)

AOP注解使用

AOP动态代理:指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式

1)、将业务逻辑组件和切面类都加入到容器中,告诉Spring哪个是切面类(@Aspect)
2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
3)、开启基于注解的aop模式:@EnableAspectJAutoProxy

text
<span style="background-color:#282b2e"><span style="color:#a9b7c6">1、导入aop模块;Spring AOP:(spring-aspects)
2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
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]、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
  		在Spring中很多的 @EnableXXX;</span></span>
  1. 导入aop模块:org.springframework.spring-aspects

    tex
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-aspects</artifactId>
    			<version>4.3.12.RELEASE</version>
    		</dependency></span></span>
  2. 定义一个业务逻辑类(MathCalculator)。在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)。

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6"><span style="color:grey">//业务类</span>
    <span style="color:#cc7832">public</span> <span style="color:#cc7832">class</span> <span style="color:#ffc66d">MathCalculator</span> {
    	
    	<span style="color:#cc7832">public</span> <span style="color:#cc7832">int</span> <span style="color:#ffc66d">div</span>(<span style="color:#cc7832">int</span> i,<span style="color:#cc7832">int</span> j){
    		System.out.println(<span style="color:#6a8759">"MathCalculator...div..."</span>);
    		<span style="color:#cc7832">return</span> i/j;	
    	}
    
    }</span></span>
  3. 定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行。通知方法:

    1. 前置通知(@Before):logStart:在目标方法(div)运行之前运行
    2. 最终通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
    3. 后置通知/返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
    4. 异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
    5. 环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.proceed())
  4. 给切面类的目标方法标注何时何地运行(通知注解)。

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6"><span style="color:grey">//@Aspect: 告诉Spring当前类是一个切面类</span>
    <span style="color:#bbb529">@Aspect</span>
    <span style="color:#cc7832">public</span> <span style="color:#cc7832">class</span> <span style="color:#ffc66d">LogAspects</span> {
    	
    	<span style="color:grey">//抽取公共的切入点表达式,空方法,只使用注解</span>
    	<span style="color:grey">//1、本类引用使用:pointCut()</span>
    	<span style="color:grey">//2、其他的切面引用使用:com.xxx.aop.LogAspects.pointCut()</span>
    	<span style="color:#bbb529">@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")</span>
    	<span style="color:#cc7832">public</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">pointCut</span>(){};
    	
    	<span style="color:grey">//前置通知,JoinPoint可以获取切入点信息</span>
    	<span style="color:grey">//@Before在目标方法之前切入,切入点表达式(指定在哪个方法切入),JoinPoint封装了切面方法信息</span>
    	<span style="color:#bbb529">@Before("pointCut()")</span>
    	<span style="color:#cc7832">public</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">logStart</span>(JoinPoint joinPoint){
    		Object[] args = joinPoint.getArgs();
    		System.out.println(<span style="color:#6a8759">""</span>+joinPoint.getSignature().getName()+<span style="color:#6a8759">"运行...@Before:参数列表是:{"</span>+Arrays.asList(args)+<span style="color:#6a8759">"}"</span>);
    	}
    	
    	<span style="color:grey">//最终通知</span>
    	<span style="color:#bbb529">@After("com.atguigu.aop.LogAspects.pointCut()")</span>
    	<span style="color:#cc7832">public</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">logEnd</span>(JoinPoint joinPoint){
    		System.out.println(<span style="color:#6a8759">""</span>+joinPoint.getSignature().getName()+<span style="color:#6a8759">"结束...@After"</span>);
    	}
    	
    	<span style="color:grey">//后置通知/返回通知,需要标明哪个参数接收返回值</span>
    	<span style="color:grey">//JoinPoint一定要出现在参数表的第一位</span>
    	<span style="color:#bbb529">@AfterReturning(value="pointCut()",returning="result")</span>
    	<span style="color:#cc7832">public</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">logReturn</span>(JoinPoint joinPoint,Object result){
    		System.out.println(<span style="color:#6a8759">""</span>+joinPoint.getSignature().getName()+<span style="color:#6a8759">"正常返回...@AfterReturning:运行结果:{"</span>+result+<span style="color:#6a8759">"}"</span>);
    	}
    	
    	<span style="color:grey">//异常通知,需要标明哪个参数接收异常</span>
    	<span style="color:#bbb529">@AfterThrowing(value="pointCut()",throwing="exception")</span>
    	<span style="color:#cc7832">public</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">logException</span>(JoinPoint joinPoint,Exception exception){
    		System.out.println(<span style="color:#6a8759">""</span>+joinPoint.getSignature().getName()+<span style="color:#6a8759">"异常...异常信息:{"</span>+exception+<span style="color:#6a8759">"}"</span>);
    	}
    
    }</span></span>
  5. 将切面类和业务逻辑类(目标方法所在类)都加入到容器中。

  6. 必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)。

  7. 给配置类中加 @EnableAspectJAutoProxy (开启基于注解的aop模式)

    • 在Spring中很多的 @EnableXXX
    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6"><span style="color:grey">//开启基于注解的aop模式</span>
    <span style="color:#bbb529">@EnableAspectJAutoProxy</span>
    <span style="color:#bbb529">@Configuration</span>
    <span style="color:#cc7832">public</span> <span style="color:#cc7832">class</span> <span style="color:#ffc66d">MainConfigOfAOP</span> {
    	 
    	<span style="color:grey">//业务逻辑类加入容器中</span>
    	<span style="color:#bbb529">@Bean</span>
    	<span style="color:#cc7832">public</span> MathCalculator <span style="color:#ffc66d">calculator</span>(){
    		<span style="color:#cc7832">return</span> <span style="color:#cc7832">new</span> MathCalculator();
    	}
    
    	<span style="color:grey">//切面类加入到容器中</span>
    	<span style="color:#bbb529">@Bean</span>
    	<span style="color:#cc7832">public</span> LogAspects <span style="color:#ffc66d">logAspects</span>(){
    		<span style="color:#cc7832">return</span> <span style="color:#cc7832">new</span> LogAspects();
    	}
    }</span></span>
  8. 测试

    • 必须使用Spring容器调用

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6"><span style="color:#cc7832">public</span> <span style="color:#cc7832">class</span> <span style="color:#ffc66d">IOCTest_AOP</span> {
      	
      	<span style="color:#bbb529">@Test</span>
      	<span style="color:#cc7832">public</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">test01</span>(){
      		AnnotationConfigApplicationContext applicationContext = <span style="color:#cc7832">new</span> AnnotationConfigApplicationContext(MainConfigOfAOP.class);
      		
      		<span style="color:grey">//1、不要自己创建对象</span>
      <span style="color:grey">//		MathCalculator mathCalculator = new MathCalculator();</span>
      <span style="color:grey">//		mathCalculator.div(1, 1);</span>
      		MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
      		
      		mathCalculator.div(<span style="color:#6897bb">1</span>, <span style="color:#6897bb">0</span>);
      		
      		applicationContext.close();
      	}
      
      }</span></span>
    • 输出

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6">div运行...<span style="color:#bbb529">@Before</span>:参数列表是{[<span style="color:#6897bb">1</span>,<span style="color:#6897bb">0</span>]}
      <span style="color:grey">//业务方法运行</span>
      MathCalculator...div...
      div结束...<span style="color:#bbb529">@After</span>
      div异常...异常信息:{java.lang.ArithmeticException: / by zero}</span></span>

⭐AOP原理

看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?

  1. 先将AnnotationAwareAspectJAutoProxyCreator(注释感知AspectJ自动代理创建器)注入容器
    0. AnnotationAwareAspectJAutoProxyCreator[BeanPostProcessor]本身也是Bean,Bean注入的过程如下:
    1. InstantiationAwareBeanPostProcessor实例化后置处理器
    2. 创建Bean实例
    3. InstantiationAwareBeanPostProcessor实例化后置处理器
    4. Bean属性赋值
    5. 初始化Bean
      0. 每一个[自定义等]初始化都要执行,过程如下:
      1. 处理Aware接口的方法回调
      2. BeanPostProcessor初始化后置处理器前置方法
      3. [自定义]初始化
      4. BeanPostProcessor初始化后置处理器后置方法

⭐开始时干了啥?@EnableAspectJAutoProxy注解

@EnableAspectJAutoProxy最终给容器中注册一个AnnotationAwareAspectJAutoProxyCreator(注解装配模式的AspectJ切面自动代理创建器)

  1. 进入@EnableAspectJAutoProxy
  2. 发现注解@Import(AspectJAutoProxyRegistrar.class)给容器中导入AspectJAutoProxyRegistrar组件
  3. 它实现了ImportBeanDefinitionRegistart,这是一个接口,可以实现自定义注册组件(在之前的注入组件文章中讲过)
  4. 它给容器自定义注册bean定义信息(BeanDefinetion) ,就是org.springframework.aop.config.internalAutoProxyCreator,类型是AnnotationAwareAspectJAutoProxyCreator(注解装配模式的AspectJ切面自动代理创建器)
  5. 并且判断@EnableAspectJAutoProxy注解并处理信息

AnnotationAwareAspectJAutoProxyCreator继承关系

java
<span style="background-color:#282b2e"><span style="color:#a9b7c6">AnnotationAwareAspectJAutoProxyCreator
	-> extends AspectJAwareAdvisorAutoProxyCreator
		-> extends AbstractAdvisorAutoProxyCreator
			-> extends AbstractAutoProxyCreator
				implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory)</span></span>

⭐大有来头?分析AnnotationAwareAspectJAutoProxyCreator

查看AnnotationAwareAspectJAutoProxyCreator继承关系中这些类的方法,找出与后置处理器和Bean工厂有关的方法,打断点观察,包括上面注入的ioc入口、业务和AOP。从父类开始:

注意区别两个不同的后置处理器

  • postProcessBeforeInstantiation  实例化前的后处理(这个是[Smart]InstantiationAwareBeanPostProcessor的)

  • postProcessBeforeInitialization  初始化前的后处理(这个是BeanPostProcessor的)

  • AbstractAutoProxyCreator(抽象自动代理创建者)
    • AbstractAutoProxyCreator.setBeanFactory()
    • AbstractAutoProxyCreator.有后置处理器的逻辑(postProcessBeforeInstantiation(实例化前的后置处理器))
  • AbstractAdvisorAutoProxyCreator.[重写]setBeanFactory()-->{ initBeanFactory() }
    • 给AbstractAdvisorAutoProxyCreator.setBeanFactory()打上断点
  • AnnotationAwareAspectJAutoProxyCreator.[重写]initBeanFactory()

⭐我注册我?注册AnnotationAwareAspectJAutoProxyCreator

“我”(指BeanPostProcessor)注册“我”(指AnnotationAwareAspectJAutoProxyCreator),这里是说AnnotationAwareAspectJAutoProxyCreator本质是BeanPostProcessor,它自己要按照BeanPostProcessor的方式注册

  通过后置处理器注入了一个后置处理器

执行过程

启动程序,首先创建容器

  1. AnnotationConfigApplicationContext传入配置类,创建ioc容器

  2. 注册配置类register(),调用refresh()刷新容器

  3. refresh()中有registerBeanPostProcessors(beanFactory)注册bean的后置处理器(注释:注册拦截 Bean 创建的 Bean 处理器),用来拦截bean的创建

  4. 后置处理器的注册逻辑:

  5. beanFactory.getBeanNamesForType()先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor(为什么更启动就有已定义的BeanPostProcessor?是因为在启动时有一个注解@EnableAspectJAutoProxy已经注册了一个AnnotationAwareAspectJAutoProxyCreator和容器中其他一些默认的,只是定义还没创建对象,在上面讲过)

    1. 根据获取的postProcessorNames,发现里面有一个org.springframework.aop.config.internalAutoProxyCreator,就是通过@EnableAspectJAutoProxy注册的AnnotationAwareAspectJAutoProxyCreator类型的属性的名字
    2. 接下来按照postProcessorNames来创建对象
    3. beanFactory.addBeanPostProcessor()给容器中加入别的BeanPostProcessor
    4. 通过postProcessorNames判断是否有实现Ordered优先级接口的,分别放在一起分步处理
      1. 优先注册实现了PriorityOrdered接口的BeanPostProcessor
      2. 再给容器中注册实现了Ordered接口的BeanPostProcessor
      3. 注册没实现优先级接口的BeanPostProcessor
      4. 执行每个优先级中的beanFactory.getBean(ppName, BeanPostProcessor.class),跳转到下一调用创建Bean
    5. 注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中(重要,每次创建Bean都要执行,BeanPostProcessor本质也是Bean)
      0. 下面创建internalAutoProxyCreatorBeanPostProcessor类型是AnnotationAwareAspectJAutoProxyCreator
      1. 创建Bean的实例(先从beanFactory.getBean()获取名字,由getBean()->doGetBean(),在doGetBean()中调getSingleton()获取单实例的bean,第一次没有,所以用singletonFactory.getObject()->createBean()->doCreateBean()->createBeanInstance()创建bean实例,下面进行初始化。如同之前讲过的BeanPostProcessor原理)
      2. populateBean(beanName,mbd,instanceWrapper):给bean的各种属性赋值
      3. initializeBean(beanName,exposedObject,mbd):初始化bean
        1. invokeAwareMethods(beanName,bean):处理Aware接口的方法回调
          1. 先判断是否是BeanFactoryAware类型,然后到达AbstractAutoProxyCreator.setBeanFactory(beanFactory)方法,就是上面分析AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator
          2. 然后执行initBeanFactory(beanFactory)初始化BeanFacotry
        2. applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
        3. invokeInitMethods(beanName,wrappedBean,mbd):执行自定义的初始化方法
        4. applyBeanPostProcessorsAfterInitialization():执行后置处理器的postProcessAfterInitialization()
      4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功
    6. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)注册到BeanFactory中,beanFactory.addBeanPostProcessor(postProcessor)BeanFactory添加新的BeanPostProcessor
      以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程

部分源码

  • 注册后置处理器

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#cc7832">public</span> <span style="color:#cc7832">static</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">registerBeanPostProcessors</span>(
    			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    
    		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, <span style="color:#cc7832">true</span>, <span style="color:#cc7832">false</span>);
    
    		<span style="color:grey">// 注册记录信息消息的BeanPostProcessorChecker</span>
    		<span style="color:grey">// bean是在BeanPostProcessor实例化期间创建的</span>
    		<span style="color:grey">// bean不适合被所有BeanPostProcessors处理。</span>
    		<span style="color:#cc7832">int</span> beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + <span style="color:#6897bb">1</span> + postProcessorNames.length;
    		beanFactory.addBeanPostProcessor(<span style="color:#cc7832">new</span> BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    
    		<span style="color:grey">// 在实现prioritordered、Ordered和其他功能的BeanPostProcessors之间分离。</span>
    		List<BeanPostProcessor> priorityOrderedPostProcessors = <span style="color:#cc7832">new</span> ArrayList<BeanPostProcessor>();
    		List<BeanPostProcessor> internalPostProcessors = <span style="color:#cc7832">new</span> ArrayList<BeanPostProcessor>();
    		List<String> orderedPostProcessorNames = <span style="color:#cc7832">new</span> ArrayList<String>();
    		List<String> nonOrderedPostProcessorNames = <span style="color:#cc7832">new</span> ArrayList<String>();
    		<span style="color:#cc7832">for</span> (String ppName : postProcessorNames) {
    			<span style="color:#cc7832">if</span> (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    				priorityOrderedPostProcessors.add(pp);
    				<span style="color:#cc7832">if</span> (pp <span style="color:#cc7832">instanceof</span> MergedBeanDefinitionPostProcessor) {
    					internalPostProcessors.add(pp);
    				}
    			}
    			<span style="color:#cc7832">else</span> <span style="color:#cc7832">if</span> (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    				orderedPostProcessorNames.add(ppName);
    			}
    			<span style="color:#cc7832">else</span> {
    				nonOrderedPostProcessorNames.add(ppName);
    			}
    		}
    
    		<span style="color:grey">// 首先,注册实现prioritordered的BeanPostProcessors。</span>
    		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
    
    		<span style="color:grey">// 接下来,注册实现Ordered的BeanPostProcessors。</span>
    		List<BeanPostProcessor> orderedPostProcessors = <span style="color:#cc7832">new</span> ArrayList<BeanPostProcessor>();
    		<span style="color:#cc7832">for</span> (String ppName : orderedPostProcessorNames) {
    			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    			orderedPostProcessors.add(pp);
    			<span style="color:#cc7832">if</span> (pp <span style="color:#cc7832">instanceof</span> MergedBeanDefinitionPostProcessor) {
    				internalPostProcessors.add(pp);
    			}
    		}
    		sortPostProcessors(orderedPostProcessors, beanFactory);
    		registerBeanPostProcessors(beanFactory, orderedPostProcessors);
    
    		<span style="color:grey">// 现在,注册所有常规的BeanPostProcessors。</span>
    		List<BeanPostProcessor> nonOrderedPostProcessors = <span style="color:#cc7832">new</span> ArrayList<BeanPostProcessor>();
    		<span style="color:#cc7832">for</span> (String ppName : nonOrderedPostProcessorNames) {
    			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    			nonOrderedPostProcessors.add(pp);
    			<span style="color:#cc7832">if</span> (pp <span style="color:#cc7832">instanceof</span> MergedBeanDefinitionPostProcessor) {
    				internalPostProcessors.add(pp);
    			}
    		}
    		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    
    		<span style="color:grey">// 最后,重新注册所有内部BeanPostProcessors。</span>
    		sortPostProcessors(internalPostProcessors, beanFactory);
    		registerBeanPostProcessors(beanFactory, internalPostProcessors);
    
    		<span style="color:grey">// 将用于检测内部bean的后处理器重新注册为applicationlistener,</span>
    		<span style="color:grey">// 将它移动到处理器链的末端(用于获取代理等)。</span>
    		beanFactory.addBeanPostProcessor(<span style="color:#cc7832">new</span> ApplicationListenerDetector(applicationContext));
    	}</span></span>
  • 属性赋值与初始化

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">		<span style="color:grey">// 初始化bean实例</span>
    		Object exposedObject = bean;
    		<span style="color:#cc7832">try</span> {
    			<span style="color:grey">// 属性赋值</span>
    			populateBean(beanName, mbd, instanceWrapper);
    			<span style="color:#cc7832">if</span> (exposedObject != <span style="color:#cc7832">null</span>) {
    				exposedObject = initializeBean(beanName, exposedObject, mbd);
    			}
    		}</span></span>
  • 初始化BeanFacotry

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">    <span style="color:#cc7832">public</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">setBeanFactory</span>(BeanFactory beanFactory) {
            <span style="color:#cc7832">super</span>.setBeanFactory(beanFactory);
            <span style="color:#cc7832">if</span> (!(beanFactory <span style="color:#cc7832">instanceof</span> ConfigurableListableBeanFactory)) {
                <span style="color:#cc7832">throw</span> <span style="color:#cc7832">new</span> IllegalArgumentException(<span style="color:#6a8759">"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: "</span> + beanFactory);
            } <span style="color:#cc7832">else</span> {
                <span style="color:grey">//初始化BeanFacotry </span>
               <span style="color:#cc7832">this</span>.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);
            }
        }</span></span>

运行时栈信息

  • beanFactory.getBeanNamesForType()先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor

  • 创建bean

  • BeanPostProcessor注册到BeanFactory中,给BeanFactory添加BeanPostProcessor

⭐你比我快?AnnotationAwareAspectJAutoProxyCreator执行时机

“你”(指AnnotationAwareAspectJAutoProxyCreator)比“我”(指BeanPostProcessor)快,这里是说AnnotationAwareAspectJAutoProxyCreator早于某些BeanPostProcessor执行,可以提前实例化一些组件

  上面代码执行后,注册了AnnotationAwareAspectJAutoProxyCreator,它是一个后置处理器,当其他组件在创建对象时,都要经过创建Bean实例、给Bean属性赋值、初始化及前后处理器,所以它可以拦截到这些组件的创建过程,接下来要看它作为后置处理器都做了什么?

执行流程

接着上面的AbstractAutoProxyCreator.setBeanFactory(beanFactory)执行,然后调用AbstractAutoProxyCreator.postProcessBeforeInstantiation(),注意区分[Smart]InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()和BeanPostProcessor.postProcessBeforeInitialization(),这一点上面分析AnnotationAwareAspectJAutoProxyCreator时也有提到,为什么会调用这个方法?在整个程序开始时,AnnotationConfigApplicationContext创建ioc容器注册配置,register()调用refresh()刷新容器,上面第(3)步执行的是registerBeanPostProcessors(beanFactory)注册bean的后置处理器方法,在它下面有一个finishBeanFactoryInitialization(beanFactory)方法

  1. finishBeanFactoryInitialization(beanFactory):完成BeanFactory初始化工作,创建剩下的单实例bean

    1. 遍历获取容器中所有的Bean,依次创建对象(这一步还没创建,只是获取,下一步才创建)

      1. DefaultListableBeanFactory.getBean(beanName)->AbstractBeanFactory.getBean()->doGetBean()->getSingleton(beanName, new ObjectFactory<Object>())=>创建Bean实例,返回一个sharedInstance属性,注释是"Create bean instance"(创建bean实例)
      2. 观察之前的代码,发现sharedInstance已经创建Object sharedInstance = getSingleton(beanName)注释是"Eagerly check singleton cache for manually registered singletons(急切地检查单例缓存中是否有手动注册的单例)"
      3. 可以发现Bean不是直接创建出来的
    2. 创建bean

      1. 先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建。只要创建好的Bean都会被缓存起来

      2. 执行getSingleton(beanName, new ObjectFactory<Object>())参数中的匿名内部类方法

      3. createBean():创建bean

        1. createBean()创建bean包括RootBeanDefinition mbd是bean的定义信息等,继续执行

        2. resolveBeforeInstantiation(beanName, mbdToUse)注释是"Give BeanPostProcessors a chance to return a proxy instead of the target bean instance"(让BeanPostProcessors有机会返回一个代理而不是目标bean实例)

          1. 解析BeforeInstantiation,希望后置处理器在此能返回一个代理对象

          2. 如果能返回代理对象就使用,如果不能就继续,后置处理器先尝试返回对象:

            • 分析:
            • AnnotationAwareAspectJAutoProxyCreator会在任何bean创建之前先尝试返回bean的实例
            • InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的
            • BeanPostProcessor是在Bean对象创建完成[自定义]初始化前后调用的
            • InstantiationAwareBeanPostProcessor是在构造方法前后执行(就在这一步),BeanPostProcessor是在Bean属性赋值[初始化之后],自定义初始化前后执行(就在下一步)】
            java
            <span style="background-color:#282b2e"><span style="color:#a9b7c6"><span style="color:grey">//拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor就执行postProcessBeforeInstantiation</span>
            bean = applyBeanPostProcessorsBeforeInstantiation():
            <span style="color:#cc7832">if</span> (bean != <span style="color:#cc7832">null</span>) {
                bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
            <span style="color:grey">//------------</span>
            <span style="color:#cc7832">if</span> (bp <span style="color:#cc7832">instanceof</span> InstantiationAwareBeanPostProcessor) {
            	ibp.postProcessBeforeInstantiation(beanClass, beanName);
            }</span></span>
        3. doCreateBean(beanName, mbdToUse, args):真正的去创建一个bean实例,包括createBeanInstance()创建Bean实例、populateBean()属性赋值、initializeBean()初始化Bean、Aware接口、前置后置等,和上一节的(3.4)一样

部分源码

  • 创建一个 Bean 实例

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:grey">/**
    	 * 此类的中心方法:创建一个 Bean 实例,
    	 * 填充 Bean 实例、应用后处理器等。
    	 * <span style="color:#808080">@see</span> #doCreateBean
    	 */</span>
    	<span style="color:#bbb529">@Override</span>
    	<span style="color:#cc7832">protected</span> Object <span style="color:#ffc66d">createBean</span>(String beanName, RootBeanDefinition mbd, Object[] args) <span style="color:#cc7832">throws</span> BeanCreationException {
    		<span style="color:#cc7832">if</span> (logger.isDebugEnabled()) {
    			logger.debug(<span style="color:#6a8759">"Creating instance of bean '"</span> + beanName + <span style="color:#6a8759">"'"</span>);
    		}
    		RootBeanDefinition mbdToUse = mbd;
    
    		<span style="color:grey">// 确保此时实际解析了 Bean 类,并且</span>
    		<span style="color:grey">// 在动态解析类的情况下克隆 Bean 定义</span>
    		<span style="color:grey">// 不能存储在共享的合并 Bean 定义中。</span>
    		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    		<span style="color:#cc7832">if</span> (resolvedClass != <span style="color:#cc7832">null</span> && !mbd.hasBeanClass() && mbd.getBeanClassName() != <span style="color:#cc7832">null</span>) {
    			mbdToUse = <span style="color:#cc7832">new</span> RootBeanDefinition(mbd);
    			mbdToUse.setBeanClass(resolvedClass);
    		}
    
    		<span style="color:grey">// 准备方法覆盖。</span>
    		<span style="color:#cc7832">try</span> {
    			mbdToUse.prepareMethodOverrides();
    		}
    		<span style="color:#cc7832">catch</span> (BeanDefinitionValidationException ex) {
    			<span style="color:#cc7832">throw</span> <span style="color:#cc7832">new</span> BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
    					beanName, <span style="color:#6a8759">"Validation of method overrides failed"</span>, ex);
    		}
    
    		<span style="color:#cc7832">try</span> {
    			<span style="color:grey">// 给 BeanPostProcessors 一个返回代理而不是目标 Bean 实例的机会。</span>
    			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    			<span style="color:#cc7832">if</span> (bean != <span style="color:#cc7832">null</span>) {
    				<span style="color:#cc7832">return</span> bean;
    			}
    		}
    		<span style="color:#cc7832">catch</span> (Throwable ex) {
    			<span style="color:#cc7832">throw</span> <span style="color:#cc7832">new</span> BeanCreationException(mbdToUse.getResourceDescription(), beanName,
    					<span style="color:#6a8759">"BeanPostProcessor before instantiation of bean failed"</span>, ex);
    		}
    		<span style="color:grey">// 实际创建指定的bean</span>
    		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    		<span style="color:#cc7832">if</span> (logger.isDebugEnabled()) {
    			logger.debug(<span style="color:#6a8759">"Finished creating instance of bean '"</span> + beanName + <span style="color:#6a8759">"'"</span>);
    		}
    		<span style="color:#cc7832">return</span> beanInstance;
    	}</span></span>
  • 尝试返回一个代理

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#cc7832">protected</span> Object <span style="color:#ffc66d">resolveBeforeInstantiation</span>(String beanName, RootBeanDefinition mbd) {
    		Object bean = <span style="color:#cc7832">null</span>;
    		<span style="color:#cc7832">if</span> (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    			<span style="color:grey">// 确保此时实际解析了 Bean 类。</span>
    			<span style="color:#cc7832">if</span> (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    				Class<?> targetType = determineTargetType(beanName, mbd);
    				<span style="color:#cc7832">if</span> (targetType != <span style="color:#cc7832">null</span>) {
    					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
    					<span style="color:#cc7832">if</span> (bean != <span style="color:#cc7832">null</span>) {
    						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    					}
    				}
    			}
    			mbd.beforeInstantiationResolved = (bean != <span style="color:#cc7832">null</span>);
    		}
    		<span style="color:#cc7832">return</span> bean;
    	}</span></span>

运行时栈信息

  • 准备实例化

⭐你先我后?创建AOP代理

“你”(指AnnotationAwareAspectJAutoProxyCreator[类型是InstantiationAwareBeanPostProcessor])先“我”(指其他某些BeanPostProcessor)后

  经过上面的流程,已经知道创建Bean需要调用AnnotationAwareAspectJAutoProxyCreator[类型是InstantiationAwareBeanPostProcessor]的后置处理器,然后才是初始化前后的BeanPostProcessor后置处理器,下面关心在AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInstantiation()中都做了什么操作

执行过程

  1. 继续上节倒数第二步,进入应用后置处理器中,每一个bean创建之前,调用InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
    0. 关心MathCalculator[业务类]LogAspect[切面类]的创建
    1. this.advisedBeans.contaionsKey(cacheKey)判断当前bean是否在advisedBeans中(保存了所有需要增强bean)?现在没有
    2. isInfrastructureClass(beanClass)判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBeanthis.aspectJAdvisorFactory.isAspect(beanClass)或者是否是切面(通过有没有@Aspect注解判断)
    3. shouldSkip(beanClass,beanName)是否需要跳过
      1. List<Advisor> candidateAdvisors = findCandidateAdvisors()找到候选的增强器(增强器就是自定义的LogAspect切面中通知方法),每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.atguigu.aop.LogAspects.logStart(org.aspectj.lang.JoinPoint)],判断每一个增强器是否是 AspectJPointcutAdvisor 类型的,是就返回true,现在都不是
  2. 然后创建bean对象后,(在初始化后)执行[AbstractAutoProxyCreator]BeanPostProcessor.postProcessAfterInitialization()
    0. 进入return wrapIfNecessary(bean, beanName, cacheKey)如有必要,就包装,只有被代理类才会创建代理对象
    1. Object[] specificInterceptors=getAdvicesAndAdvisorsForBean(bean.getClass(),beanName,null)注释是Create proxy if we have advice(如果我们有通知方法,请创建代理)获取当前bean的所有增强器(通知方法),进入
      1. findEligibleAdvisors(beanClass,beanName)找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
      2. 获取到能在bean使用的增强器,如切入点表达式
      3. 给增强器排序
    2. 已经获取到可用增强器,保存当前bean在已增强集合中this.advisedBeans.put()
    3. 如果当前bean需要增强,创建当前bean的代理对象Object proxy = createProxy()
      1. 获取所有增强器(通知方法)
      2. 保存到proxyFactory
      3. 创建代理对象proxyFactory.getProxy(getProxyClassLoader()):Spring自动决定两种方式
        • JdkDynamicAopProxy(config):jdk动态代理(需要接口);
        • ObjenesisCglibAopProxy(config):cglib的动态代理;
      4. 创建完成后得到的bean的增强代理对象
    4. 给容器中返回当前组件使用cglib增强了的代理对象
    5. 以后容器中获取到的就是这个组件的代理对象MathCalculator(业务类)$EnhancerBySpringCGLIB,执行目标方法的时候,代理对象就会执行通知方法的流程

部分源码

  • 如果必要包装

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:grey">//必要时包装给定的bean,即,如果它符合被代理的条件。</span>
    	<span style="color:#cc7832">protected</span> Object <span style="color:#ffc66d">wrapIfNecessary</span>(Object bean, String beanName, Object cacheKey) {
    		<span style="color:grey">//...</span>
    		<span style="color:grey">// 如果我们有建议,请创建代理。</span>
    		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, <span style="color:#cc7832">null</span>);
    		<span style="color:#cc7832">if</span> (specificInterceptors != DO_NOT_PROXY) {
    			<span style="color:grey">// 保存可用增强器</span>
    			<span style="color:#cc7832">this</span>.advisedBeans.put(cacheKey, Boolean.TRUE);
    			<span style="color:grey">// 创建代理对象</span>
    			Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, <span style="color:#cc7832">new</span> SingletonTargetSource(bean));
    			<span style="color:#cc7832">this</span>.proxyTypes.put(cacheKey, proxy.getClass());
    			<span style="color:#cc7832">return</span> proxy;
    		}
    
    		<span style="color:#cc7832">this</span>.advisedBeans.put(cacheKey, Boolean.FALSE);
    		<span style="color:#cc7832">return</span> bean;
    	}
    </span></span>
  • 创建代理

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:grey">// 创建一个CGLIB代理或JDK动态代理。</span>
    	<span style="color:#bbb529">@Override</span>
    	<span style="color:#cc7832">public</span> AopProxy <span style="color:#ffc66d">createAopProxy</span>(AdvisedSupport config) <span style="color:#cc7832">throws</span> AopConfigException {
    		<span style="color:#cc7832">if</span> (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    			Class<?> targetClass = config.getTargetClass();
    			<span style="color:#cc7832">if</span> (targetClass == <span style="color:#cc7832">null</span>) {
    				<span style="color:#cc7832">throw</span> <span style="color:#cc7832">new</span> AopConfigException(<span style="color:#6a8759">"TargetSource cannot determine target class: "</span> +
    						<span style="color:#6a8759">"Either an interface or a target is required for proxy creation."</span>);
    			}
    			<span style="color:grey">// 判断是否接口</span>
    			<span style="color:#cc7832">if</span> (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    				<span style="color:grey">// 创建JDK动态代理</span>
    				<span style="color:#cc7832">return</span> <span style="color:#cc7832">new</span> JdkDynamicAopProxy(config);
    			}
    			<span style="color:grey">// 创建CGLIB代理</span>
    			<span style="color:#cc7832">return</span> <span style="color:#cc7832">new</span> ObjenesisCglibAopProxy(config);
    		}
    		<span style="color:#cc7832">else</span> {
    			<span style="color:#cc7832">return</span> <span style="color:#cc7832">new</span> JdkDynamicAopProxy(config);
    		}
    	}</span></span>

⭐如此包装?获取拦截器链MethodInterceptor

如此“包装”(将切入点增强器包装为方法拦截器)

  接着上面代码执行,在上面已经获取到被代理后的对象,现在需要把所有的增强方法转为MethodInterceptor类型。

执行过程

  1. (被代理后的)目标方法执行:容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx)

    1. debug 从ioc容器中的目标方法执行开始进入下一步(或者:入-出-出-入-出-入-出-入)

    2. CglibAopProxy.intercept():拦截目标方法的执行

    3. 根据ProxyFactory对象获取将要执行的目标方法拦截器链:List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)

      1. List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length)保存所有拦截器,拦截器列表长度就是config.getAdvisors()长度,等于5。包括一个默认的ExposeInvocationInterceptor 和 4个(自定义)增强器
      2. 遍历所有的增强器,如果是切入点的增强器,将其转为拦截器MethodInterceptorMethodInterceptor[] interceptor = registry.getInterceptors(advisor)
        3. 将增强器转为List<MethodInterceptor>拦截器
        1. 如果是MethodInterceptor,直接加入到集合中
        2. 如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor
          3. 转换完成返回MethodInterceptor数组
    4. 或者本身是Interceptor,或者由其他类型转为MethodInterceptor,最终返回拦截器列表(此次是5个)

  2. 如果没有拦截器链chain.isEmpty(),直接执行目标方法methodProxy.invoke()

    1. 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation 对象,并调用 Object retVal = new CglibMethodInvocation(proxy,traget,method,args,targetClass,chain,methodProxy).proceed()继续执行

部分源码

  • 代理对象刚执行时的拦截方法

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">		<span style="color:#bbb529">@Override</span>
    		<span style="color:#cc7832">public</span> Object <span style="color:#ffc66d">intercept</span>(Object proxy, Method method, Object[] args, MethodProxy methodProxy) <span style="color:#cc7832">throws</span> Throwable {
    			Object oldProxy = <span style="color:#cc7832">null</span>;
    			<span style="color:#cc7832">boolean</span> setProxyContext = <span style="color:#cc7832">false</span>;
    			Class<?> targetClass = <span style="color:#cc7832">null</span>;
    			Object target = <span style="color:#cc7832">null</span>;
    			<span style="color:#cc7832">try</span> {
    				<span style="color:#cc7832">if</span> (<span style="color:#cc7832">this</span>.advised.exposeProxy) {
    					<span style="color:grey">// 在必要时使调用可用。</span>
    					oldProxy = AopContext.setCurrentProxy(proxy);
    					setProxyContext = <span style="color:#cc7832">true</span>;
    				}
    				<span style="color:grey">// 可能为空。尽可能晚地减少我们“拥有”目标的时间,以防它来自池...</span>
    				target = getTarget();
    				<span style="color:#cc7832">if</span> (target != <span style="color:#cc7832">null</span>) {
    					targetClass = target.getClass();
    				}
    				<span style="color:grey">// 获取拦截器链</span>
    				List<Object> chain = <span style="color:#cc7832">this</span>.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    				Object retVal;
    				<span style="color:grey">// 检查是否有拦截器链</span>
    				<span style="color:#cc7832">if</span> (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
    					<span style="color:grey">// 我们可以跳过创建方法调用:只需直接调用目标即可。请注意,最终的调用程序必须是 InvokerInterceptor,因此我们知道它只对目标执行反射操作,并且没有热插拔或花哨的代理。</span>
    					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    					retVal = methodProxy.invoke(target, argsToUse);
    				}
    				<span style="color:#cc7832">else</span> {
    					<span style="color:grey">// 我们需要创建一个方法调用(执行目标方法)...</span>
    					retVal = <span style="color:#cc7832">new</span> CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    				}
    				retVal = processReturnType(proxy, target, method, retVal);
    				<span style="color:#cc7832">return</span> retVal;
    			}
    			<span style="color:grey">//...</span>
    		}</span></span>
  • 包装拦截器

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#bbb529">@Override</span>
    	<span style="color:#cc7832">public</span> List<Object> <span style="color:#ffc66d">getInterceptorsAndDynamicInterceptionAdvice</span>(
    			Advised config, Method method, Class<?> targetClass) {
    
    		<span style="color:grey">// 这有点棘手...我们必须首先处理介绍,但我们需要保持最终列表中的秩序。</span>
    		List<Object> interceptorList = <span style="color:#cc7832">new</span> ArrayList<Object>(config.getAdvisors().length);
    		Class<?> actualClass = (targetClass != <span style="color:#cc7832">null</span> ? targetClass : method.getDeclaringClass());
    		<span style="color:#cc7832">boolean</span> hasIntroductions = hasMatchingIntroductions(config, actualClass);
    		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    
    		<span style="color:#cc7832">for</span> (Advisor advisor : config.getAdvisors()) {
    			<span style="color:#cc7832">if</span> (advisor <span style="color:#cc7832">instanceof</span> PointcutAdvisor) {
    				<span style="color:grey">// 有条件地添加它。</span>
    				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
    				<span style="color:#cc7832">if</span> (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
    					<span style="color:grey">// 转为拦截器</span>
    					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
    					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
    					<span style="color:#cc7832">if</span> (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
    						<span style="color:#cc7832">if</span> (mm.isRuntime()) {
    							<span style="color:grey">// 在 getInterceptors()方法中创建新的对象实例不是问题,因为我们通常缓存创建的链。</span>
    							<span style="color:#cc7832">for</span> (MethodInterceptor interceptor : interceptors) {
    								interceptorList.add(<span style="color:#cc7832">new</span> InterceptorAndDynamicMethodMatcher(interceptor, mm));
    							}
    						}
    						<span style="color:#cc7832">else</span> {
    							interceptorList.addAll(Arrays.asList(interceptors));
    						}
    					}
    				}
    			}
    			<span style="color:#cc7832">else</span> <span style="color:#cc7832">if</span> (advisor <span style="color:#cc7832">instanceof</span> IntroductionAdvisor) {
    				<span style="color:grey">// ...将其余类型都转为拦截器</span>
    			}
    		<span style="color:#cc7832">return</span> interceptorList;
    	}</span></span>

⭐喵啊?链式调用通知方法

妙啊,执行过程设计的很有趣

  所有准备都做好了(创建代理,增强器排序(倒序),增强器包装获取拦截器链),现在开始调用通知方法

执行过程

  1. 拦截器链的触发过程:
    1. 如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(执行到了最后一个拦截器)执行目标方法
    2. 链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行。拦截器链的机制,保证通知方法与目标方法的执行顺序

5个拦截器(1个默认+4个自定义)的执行顺序

执行上一节最后一步,获取到拦截器链后执行new CglibMethodInvocation(proxy,traget,method,args,targetClass,chain,methodProxy).proceed()proceed()方法

  1. 进入proceed()方法,先判断currentInterceptorIndex索引的值,默认是-1。this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1 -->{return invokeJoinpoint()}
  2. 判断是否有拦截器,如果没有 0 - 1 = -1,正好等于默认值,没有拦截器,就直接执行目标方法(业务)method.invoke(target,args)
  3. 判断是否是否要执行目标方法。程序多次执行,每加载一个拦截器,就+1,直到最后一个拦截器时,this.currentInterceptorIndex=4(从-1到4),判断4 == 5 - 1,拦截器加载完了,开始执行目标方法(业务)。
  4. 开始执行
    1. -1 == 5 - 1 不通过,表示有拦截器,执行this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex),从-1到0,获取第0号拦截器。
    2. 第 [0] 号拦截器是默认拦截器ExposenvocationInterceptor调用invoke(this),参数this就是被代理目标类(业务类)CgliMethodInvocation,进入invoke(this),里面调用mi[MethodInvocation].proceed()这个proceed()就是本节第(1)步的proceed(),每个拦截器都会执行
    3. 获取索引为 [1] 的拦截器AspectJAfterThrowingAdvice前置拦截器->判断->自增->invoke(this)->mi.proceed()
    4. 获取索引为 [2] 的拦截器AfterReturingAdviceInterceptor返回通知拦截器->判断->自增->invoke(this)->mi.proceed()
    5. 获取索引为 [3] 的拦截器AspectJAfterAdvice->判断->自增->invoke(this)->mi.proceed()
    6. 获取索引为 [4] 的拦截器MethodBeforeAdviceInterceptor前置拦截器->判断->自增->invoke(this)这里与之前不同,因为是前置通知,所以要在目标方法执行前先执行增强方法,this.advice.before(mi.getMethod(),mi.getArguments(),mi.getThis())此时执行自定义的前置通知 }->mi.proceed()
    7. 执行完最后一个拦截器,满足条件4 = 5 - 1,所以进入判断执行invokeJoinpoint()利用反射执行目标方法(业务),到达底部同时准备返回
  5. 开始返回
  6. 执行完目标方法,返回到第 [3] 个拦截器AspectJAfterAdvice执行最终通知,不管是否有异常finally{ invokeAdviceMethod(getJoinPointMatch(),null,null) }
  7. 继续返回,到第 [2] 个拦截器,AfterReturingAdviceInterceptor执行返回通知,但是目标方法抛了异常,此处代码将异常继续上抛throws Throwable,所以此处不做任何执行,如果没有异常,就正常调用返回通知this.advice.afterReturning()
  8. 继续返回,到第 [1] 个拦截器,AfterReturingAdviceInterceptor执行异常通知,它可以处理异常 catch(Throwable ex){ if(){invokeAdviceMethod(getJoinPointMatch(),null,ex)} throw ex }
  9. 继续返回,自定义增强方法执行完了,执行第 [0] 个默认拦截器
  10. 增强方法执行过程:逆向执行拦截器,到达底部执行目标方法,返回时正向执行增强方法

部分源码

  • 获取拦截器后继续方法调用

    java
    <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#bbb529">@Override</span>
    	<span style="color:#cc7832">public</span> Object <span style="color:#ffc66d">proceed</span>() <span style="color:#cc7832">throws</span> Throwable {
    		<span style="color:grey">//	我们从 -1 的索引开始,并提前递增。</span>
    		<span style="color:#cc7832">if</span> (<span style="color:#cc7832">this</span>.currentInterceptorIndex == <span style="color:#cc7832">this</span>.interceptorsAndDynamicMethodMatchers.size() - <span style="color:#6897bb">1</span>) {
    			<span style="color:#cc7832">return</span> invokeJoinpoint();
    		}
    
    		<span style="color:grey">// 每次将索引自增</span>
    		Object interceptorOrInterceptionAdvice =
    				<span style="color:#cc7832">this</span>.interceptorsAndDynamicMethodMatchers.get(++<span style="color:#cc7832">this</span>.currentInterceptorIndex);
    		<span style="color:#cc7832">if</span> (interceptorOrInterceptionAdvice <span style="color:#cc7832">instanceof</span> InterceptorAndDynamicMethodMatcher) {
    			<span style="color:grey">// 在此处评估动态方法匹配器:静态部分将已经过评估并发现匹配。</span>
    			InterceptorAndDynamicMethodMatcher dm =
    					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    			<span style="color:#cc7832">if</span> (dm.methodMatcher.matches(<span style="color:#cc7832">this</span>.method, <span style="color:#cc7832">this</span>.targetClass, <span style="color:#cc7832">this</span>.arguments)) {
    				<span style="color:#cc7832">return</span> dm.interceptor.invoke(<span style="color:#cc7832">this</span>);
    			}
    			<span style="color:#cc7832">else</span> {
    				<span style="color:grey">// 动态匹配失败。</span>
    				<span style="color:grey">// 跳过此侦听器并调用链中的下一个侦听器。</span>
    				<span style="color:#cc7832">return</span> proceed();
    			}
    		}
    		<span style="color:#cc7832">else</span> {
    			<span style="color:grey">// 调用这个</span>
    			<span style="color:grey">// 它是一个拦截器,所以我们只需调用它:在构造此对象之前,切入点将进行静态计算。</span>
    			<span style="color:#cc7832">return</span> ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(<span style="color:#cc7832">this</span>);
    		}
    	}</span></span>
  • 依次调用拦截器的mi.proceed()

    • 异常通知:AspectJAfterThrowingAdvice

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#bbb529">@Override</span>
      	<span style="color:#cc7832">public</span> Object <span style="color:#ffc66d">invoke</span>(MethodInvocation mi) <span style="color:#cc7832">throws</span> Throwable {
      		<span style="color:#cc7832">try</span> {
      			<span style="color:#cc7832">return</span> mi.proceed();
      		}
      		<span style="color:#cc7832">catch</span> (Throwable ex) {
      			<span style="color:#cc7832">if</span> (shouldInvokeOnThrowing(ex)) {
      				invokeAdviceMethod(getJoinPointMatch(), <span style="color:#cc7832">null</span>, ex);
      			}
      			<span style="color:#cc7832">throw</span> ex;
      		}
      	}</span></span>
    • 返回通知:AspectJAfterReturningAdvice

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#bbb529">@Override</span>
      	<span style="color:#cc7832">public</span> Object <span style="color:#ffc66d">invoke</span>(MethodInvocation mi) <span style="color:#cc7832">throws</span> Throwable {
      		Object retVal = mi.proceed();
      		<span style="color:#cc7832">this</span>.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
      		<span style="color:#cc7832">return</span> retVal;
      	}</span></span>
    • 后置通知:AspectJAfterAdvice

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#bbb529">@Override</span>
      	<span style="color:#cc7832">public</span> Object <span style="color:#ffc66d">invoke</span>(MethodInvocation mi) <span style="color:#cc7832">throws</span> Throwable {
      		<span style="color:#cc7832">try</span> {
      			<span style="color:#cc7832">return</span> mi.proceed();
      		}
      		<span style="color:#cc7832">finally</span> {
      			invokeAdviceMethod(getJoinPointMatch(), <span style="color:#cc7832">null</span>, <span style="color:#cc7832">null</span>);
      		}
      	}</span></span>
    • 前置通知:AspectJMethodBeforeAdvice

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#bbb529">@Override</span>
      	<span style="color:#cc7832">public</span> Object <span style="color:#ffc66d">invoke</span>(MethodInvocation mi) <span style="color:#cc7832">throws</span> Throwable {
      		<span style="color:#cc7832">this</span>.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
      		<span style="color:#cc7832">return</span> mi.proceed();
      	}</span></span>
  • 调完拦截器之后执行目标方法

    • 满足条件执行目标方法

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6">		<span style="color:grey">//	我们从-1的索引和早期的增量开始。</span>
      		<span style="color:#cc7832">if</span> (<span style="color:#cc7832">this</span>.currentInterceptorIndex == <span style="color:#cc7832">this</span>.interceptorsAndDynamicMethodMatchers.size() - <span style="color:#6897bb">1</span>) {
      			<span style="color:#cc7832">return</span> invokeJoinpoint();
      		}</span></span>
    • 然后一层层向上返回拦截器,并处理通知(除了前置通知,因为它已经在目标方法前执行了

    • 如下:它返回到异常通知拦截器,并处理异常

      java
      <span style="background-color:#282b2e"><span style="color:#a9b7c6">	<span style="color:#bbb529">@Override</span>
      	<span style="color:#cc7832">public</span> Object <span style="color:#ffc66d">invoke</span>(MethodInvocation mi) <span style="color:#cc7832">throws</span> Throwable {
      		<span style="color:#cc7832">try</span> {
      			<span style="color:#cc7832">return</span> mi.proceed();
      		}
      		<span style="color:#cc7832">catch</span> (Throwable ex) {
      			<span style="color:#cc7832">if</span> (shouldInvokeOnThrowing(ex)) {
      				<span style="color:grey">//处理异常</span>
      				invokeAdviceMethod(getJoinPointMatch(), <span style="color:#cc7832">null</span>, ex);
      			}
      			<span style="color:#cc7832">throw</span> ex;
      		}
      	}</span></span>

总结

  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. 效果:
        正常执行:前置通知-》目标方法-》后置通知-》返回通知
        出现异常:前置通知-》目标方法-》后置通知-》异常通知

转自:浅尝Spring注解开发_AOP原理及完整过程分析(源码) - 蔚然丶丶 - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值