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

浅尝Spring注解开发,基于Spring 4.3.12

分析AOP执行过程及源码,包含AOP注解使用、AOP原理、分析AnnotationAwareAspectJAutoProxyCreator、AOP代理、拦截器、链式调用

以初学者的角度跟着雷丰阳的视频走完AOP整个过程,设计很巧妙。补充了自己的理解,为了流程连续性,所以全放在放在一篇里,如有错误请多多指教。

浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配

浅尝Spring注解开发_Bean生命周期及执行过程

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

AOP注解使用

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

1)、将业务逻辑组件和切面类都加入到容器中,告诉Spring哪个是切面类(@Aspect)

2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)

3)、开启基于注解的aop模式:@EnableAspectJAutoProxy

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;
  1. 导入aop模块:org.springframework.spring-aspects

    		<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</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运行到哪里然后执行。通知方法:

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

    //@Aspect: 告诉Spring当前类是一个切面类
    @Aspect
    public class LogAspects { //抽取公共的切入点表达式,空方法,只使用注解
    //1、本类引用使用:pointCut()
    //2、其他的切面引用使用:com.xxx.aop.LogAspects.pointCut()
    @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
    public void pointCut(){}; //前置通知,JoinPoint可以获取切入点信息
    //@Before在目标方法之前切入,切入点表达式(指定在哪个方法切入),JoinPoint封装了切面方法信息
    @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+"}");
    } }
  5. 将切面类和业务逻辑类(目标方法所在类)都加入到容器中。

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

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

    • 在Spring中很多的 @EnableXXX
    //开启基于注解的aop模式
    @EnableAspectJAutoProxy
    @Configuration
    public class MainConfigOfAOP { //业务逻辑类加入容器中
    @Bean
    public MathCalculator calculator(){
    return new MathCalculator();
    } //切面类加入到容器中
    @Bean
    public LogAspects logAspects(){
    return new LogAspects();
    }
    }
  8. 测试

    • 必须使用Spring容器调用

      public class IOCTest_AOP {
      
      	@Test
      public void test01(){
      AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class); //1、不要自己创建对象
      // MathCalculator mathCalculator = new MathCalculator();
      // mathCalculator.div(1, 1);
      MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); mathCalculator.div(1, 0); applicationContext.close();
      } }
    • 输出

      div运行...@Before:参数列表是{[1,0]}
      //业务方法运行
      MathCalculator...div...
      div结束...@After
      div异常...异常信息:{java.lang.ArithmeticException: / by zero}

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继承关系

AnnotationAwareAspectJAutoProxyCreator
-> extends AspectJAwareAdvisorAutoProxyCreator
-> extends AbstractAdvisorAutoProxyCreator
-> extends AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory)

大有来头?分析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的过程

部分源码

  • 注册后置处理器

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

    		// 初始化bean实例
    Object exposedObject = bean;
    try {
    // 属性赋值
    populateBean(beanName, mbd, instanceWrapper);
    if (exposedObject != null) {
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    }
  • 初始化BeanFacotry

        public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
    throw new IllegalArgumentException("AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
    } else {
    //初始化BeanFacotry
    this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);
    }
    }

运行时栈信息

  • 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属性赋值[初始化之后],自定义初始化前后执行(就在下一步)】
            //拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor就执行postProcessBeforeInstantiation
            bean = applyBeanPostProcessorsBeforeInstantiation():
            if (bean != null) {
            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
            //------------
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
            ibp.postProcessBeforeInstantiation(beanClass, beanName);
            }
        3. doCreateBean(beanName, mbdToUse, args):真正的去创建一个bean实例,包括createBeanInstance()创建Bean实例、populateBean()属性赋值、initializeBean()初始化Bean、Aware接口、前置后置等,和上一节的(3.4)一样

部分源码

  • 创建一个 Bean 实例

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

    	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    // 确保此时实际解析了 Bean 类。
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    Class<?> targetType = determineTargetType(beanName, mbd);
    if (targetType != null) {
    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
    if (bean != null) {
    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    }
    }
    }
    mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
    }

运行时栈信息

  • 准备实例化

你先我后?创建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,执行目标方法的时候,代理对象就会执行通知方法的流程

部分源码

  • 如果必要包装

    	//必要时包装给定的bean,即,如果它符合被代理的条件。
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //...
    // 如果我们有建议,请创建代理。
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    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;
    }
  • 创建代理

    	// 创建一个CGLIB代理或JDK动态代理。
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    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.");
    }
    // 判断是否接口
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    // 创建JDK动态代理
    return new JdkDynamicAopProxy(config);
    }
    // 创建CGLIB代理
    return new ObjenesisCglibAopProxy(config);
    }
    else {
    return new JdkDynamicAopProxy(config);
    }
    }

如此包装?获取拦截器链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()继续执行

部分源码

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

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

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

喵啊?链式调用通知方法

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

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

执行过程

  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. 增强方法执行过程:逆向执行拦截器,到达底部执行目标方法,返回时正向执行增强方法

部分源码

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

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

    • 异常通知:AspectJAfterThrowingAdvice

      	@Override
      public Object invoke(MethodInvocation mi) throws Throwable {
      try {
      return mi.proceed();
      }
      catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
      invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
      }
      }
    • 返回通知:AspectJAfterReturningAdvice

      	@Override
      public Object invoke(MethodInvocation mi) throws Throwable {
      Object retVal = mi.proceed();
      this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
      return retVal;
      }
    • 后置通知:AspectJAfterAdvice

      	@Override
      public Object invoke(MethodInvocation mi) throws Throwable {
      try {
      return mi.proceed();
      }
      finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
      }
      }
    • 前置通知:AspectJMethodBeforeAdvice

      	@Override
      public Object invoke(MethodInvocation mi) throws Throwable {
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
      return mi.proceed();
      }
  • 调完拦截器之后执行目标方法

    • 满足条件执行目标方法

      		//	我们从-1的索引和早期的增量开始。
      if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
      }
    • 然后一层层向上返回拦截器,并处理通知(除了前置通知,因为它已经在目标方法前执行了)

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

      	@Override
      public Object invoke(MethodInvocation mi) throws Throwable {
      try {
      return mi.proceed();
      }
      catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
      //处理异常
      invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
      }
      }

总结

  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原理及完整过程分析(源码)的更多相关文章

  1. 浅尝Spring注解开发_Servlet3.0与SpringMVC

    浅尝Spring注解开发_Servlet 3.0 与 SpringMVC 浅尝Spring注解开发,基于Spring 4.3.12 Servlet3.0新增了注解支持.异步处理,可以省去web.xml ...

  2. 浅尝Spring注解开发_Bean生命周期及执行过程

    Spring注解开发 浅尝Spring注解开发,基于Spring 4.3.12 包含Bean生命周期.自定义初始化方法.Debug BeanPostProcessor执行过程及在Spring底层中的应 ...

  3. 浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配

    Spring注解开发 浅尝Spring注解开发,基于Spring 4.3.12 包含自定义扫描组件.自定义导入组件.手动注册组件.自动注入方法和参数.使用Spring容器底层组件等 配置 @Confi ...

  4. spring注解开发-扩展原理(源码)

    1.BeanFactoryPostProcessor BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的; BeanFactoryPostProcesso ...

  5. Spring注解开发_Spring容器创建概述

    浅尝Spring注解开发_Spring容器创建概述 浅尝Spring注解开发,基于Spring 4.3.12 概述Spring容器创建的过程,包括12个方法的执行 浅尝Spring注解开发_自定义注册 ...

  6. Spring注解开发-全面解析常用注解使用方法之生命周期

    本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring注解开发-全面解析常用注解使用方法之组件注册 bean生命周期 ​ ...

  7. Annotation(三)——Spring注解开发

    Spring框架的核心功能IoC(Inversion of Control),也就是通过Spring容器进行对象的管理,以及对象之间组合关系的映射.通常情况下我们会在xml配置文件中进行action, ...

  8. spring注解开发中常用注解以及简单配置

    一.spring注解开发中常用注解以及简单配置 1.为什么要用注解开发:spring的核心是Ioc容器和Aop,对于传统的Ioc编程来说我们需要在spring的配置文件中邪大量的bean来向sprin ...

  9. JAVAEE——SSH项目实战06:统计信息管理、Spring注解开发和EasyUI

    作者: kent鹏 转载请注明出处: http://www.cnblogs.com/xieyupeng/p/7190925.html 一.统计信息管理   二.Spring注解开发 1.service ...

随机推荐

  1. Oracle入门基础(十三)一一java调用oracle存储过程

    package demo; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultS ...

  2. java线程池源码分析

    我们在关闭线程池的时候会使用shutdown()和shutdownNow(),那么问题来了: 这两个方法又什么区别呢? 他们背后的原理是什么呢? 线程池中线程超过了coresize后会怎么操作呢? 为 ...

  3. 简述 synchronized 和 java.util.concurrent.locks.Lock 的异同?

    Lock 是 Java 5 以后引入的新的 API,和关键字 synchronized 相比主要相同点: Lock 能完成 synchronized 所实现的所有功能:主要不同点:Lock 有比 sy ...

  4. SpringDataJpa使用审计(Auditing)功能

    SpringBoot项目使用SpringDataJpa提供的审计功能的使用流程 SpringDataJpa提供审计注解:@CreatedBy,@LastModifiedBy,@CreatedDate, ...

  5. memcached 是原子的吗?

    所有的被发送到 memcached 的单个命令是完全原子的.如果您针对同一份数据 同时发送了一个 set 命令和一个 get 命令,它们不会影响对方.它们将被串行化. 先后执行.即使在多线程模式,所有 ...

  6. 不同版本的 Spring Framework 有哪些主要功能?

    Version Feature Spring 2.5 发布于 2007 年.这是第一个支持注解的版本. Spring 3.0 发布于 2009 年.它完全利用了 Java5 中的改进,并为 JEE6 ...

  7. nRF Connect SDK(NCS)/Zephyr固件升级详解 – 重点讲述MCUboot和蓝牙空中升级

    如何在nRF Connect SDK(NCS)中实现蓝牙空中升级?MCUboot和B0两个Bootloader有什么区别?MCUboot升级使用的image格式是怎么样的?什么是SMP协议?CBOR编 ...

  8. C++ | 虚函数初探

    虚函数 虚函数 是在基类中使用关键字 virtual 声明的函数.在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数. 我们想要的是在程序中任意点可以根据所调用的对象类型来选择调 ...

  9. vim的vimrc配置

    windows "# modified by Neoh set helplang=cn "使用中文帮助文档 set encoding=utf-8 "查看utf-8格式的帮 ...

  10. React 和 ES6 工作流之 Webpack的使用(第六部分)

    这是React和ECMAScript2015系列文章的最后一篇,我们将继续探索React 和 Webpack的使用. 下面是所有系列文章章节的链接: React . ES6 - 介绍(第一部分) Re ...