上一节对doGetBean()方法为入口,进行bean的注册、实例化、属性赋值等操作进行了说明。本章内容主要是针对前置、后置处理进行说明,主要围绕AOP进行理解。
先认识下面3个方法:
applyBeanPostProcessorsBeforeInstantiation:前置处理器实例化
applyBeanPostProcessorsAfterInitialization:后置处理器初始化
applyBeanPostProcessorsBeforeInitialization:前置处理器初始化
其中在AbstractAutowireCapableBeanFactory.resolveBeforeInstantiationy用到了applyBeanPostProcessorsBeforeInstantiation、applyBeanPostProcessorsAfterInitialization。
在AbstractAutowireCapableBeanFactory.initializeBean用到了applyBeanPostProcessorsAfterInitialization、applyBeanPostProcessorsBeforeInitialization
因为这3个方法在不同的地方都被调用过,而且Aop与这几个方法密切相关。总的来说:
applyBeanPostProcessorsBeforeInstantiation,会被调用,基本上用处不大,逻辑也不复杂。该方法跟后置方法很类似。
applyBeanPostProcessorsBeforeInitialization,也是会被调用,基本上用处不大,逻辑也不复杂。
applyBeanPostProcessorsAfterInitialization,如果实现了aop之后,被代理的类在这个方法中还是挺复杂的。可以以这个方法为一个研究点(打个断点)。
对于一个普通bean来说,初始化流程是(主要的逻辑在AbstractAutowireCapableBeanFactory.doCreateBean()方法里面):
由RootBeanDefinition封装为beanWrapperImpl,然后实例化createBeanInstance(),然后属性赋值populateBean(), 前置初始化bean(比如为aware的bean设置context),然后执行invokeInitMethods,执行初始化方法,然后后置初始化bean(与前置一样,只是方法不同)。
没有被aop代理的类不会执行到wrapIfNecessary()方法的查找增强型方法那里去。比如判断是否是增强的bean,是否有@aspenct注解的,是否在该类中寻找到了需要切入的方法。执行器BeanPostProcessor不会进入该方法,因为他本身就是执行器调入的方法。有@aspenct注解的会提前返回bean,没有需要切入方法的bean因为找不到advise,也不会被代理。
首先在总调度refresh()中的registerBeanPostProcessors()方法中会对实现了BeanPostProcessor接口的方法进行初始化。比如aop默认名“org.springframework.aop.config.internalAutoProxyCreator”,AnnotationAwareAspectJAutoProxyCreator类进行实例化。这个实例化跟普通的bean实例化没有区别。只是比普通的bean提前实例化了。
添加了@Aspect注解的bean类实例化也跟普通类没有什么区别。
但是被代理的bean实例化会复杂点。
1查找有注解@Aspect的类(这个是在applyBeanPostProcessorsBeforeInstantiation)查找的。
[if !supportLists]2 [endif] 根据注解pointcut\after\before\around获取增强器。
每个方法对应一个增强类。
[if !supportLists]3 [endif] 用cglib创建代理类。
cglib设置了superclass即被代理的类之后,就需要设置setCallback回调类,这个类需要实现MethodInterceptor接口。
配置了Aop注解之后,首先是怎么去得到这些切入方法的呢?
在applyBeanPostProcessorsBeforeInstantiation方法中,其实去获取这些切入方法是比较隐蔽的。在一个判断是否直接返回bean的方法shouldSkip()中进行的。查找需求切入的方法如下:
[if !supportLists]1、 [endif]在beanfactroy中提取到所有的bean,然后找到有注解的@aspect的类
[if !supportLists]2、 [endif]根据事先预设好的@before\@after\@around等注解的找到代理方法,当然这里要做一些判断,比如要判断是否有pointcut,切入方法跟需要代理的方法是否一致等等。
[if !supportLists]3、 [endif]在对bean进行实例化时,会对每个bean进行判断,判断该类是否需要aop增强,根据找到的需要切入的方法进行匹配,看该类是否有该方法。判断的过程是比较复杂的。
[if !supportLists]4、 [endif]根据注解方法,每个方法都生成一个对应的增强类:
InstantiationModelAwarePointcutAdvisorImpl这个类里面也对应了AbstractAspectJAdvice增强类。因为before\after\around等都对应一个增强类。比如AspectJAfterAdvice、AspectJMethodBeforeAdvice等等方法。这些类的调用顺序在后面代理的类执行的时候是设定好的。
那么其实每个切入的方法都对应了一个InstantiationModelAwarePointcutAdvisorImpl这样的advise类,然后最后生成的代理类也是用到了这些类。
对应代理类的生成用到的是cglib,底层用的是asm,这个框架在后面专门说明。这些框架技术只是固定的模式。
spring用cglib生成的代理类,最重要的一步其实就是生成callback接口的实现类,MethodInterceptor接口也是继承的这个类。 spring用的内部类DynamicAdvisedInterceptor实现的这个类。之前的增强类InstantiationModelAwarePointcutAdvisorImpl被以数组的方式赋值到advised里面。 实现了MethodInterceptor之后,会被调用intercept()方法。这里使用的ReflectiveMethodInvocation.proceed 调用链,
interceptorsAndDynamicMethodMatchers按照数组调用,设计的很巧。而且顺序是固定的。虽然AspectJAfterAdvice.invoke方法最先被调用,但是after方法是在finally块最后被调用的。
每个切入点方法都会对应一个增强类,获取到了代理类实例之后,采用反射的方式获取到对象的方法:object.getClass().getMethod(),method.invoke(object)去执行方法。