Spring源码分析之 AOP(一,创建代理对象)
一,@EnableAspectJAutoProxy开启AspectJ自动代理
在这个注解中导入了一个@Import(AspectJAutoProxyRegistrar.class)类。这个类实现了ImportBeanDefinitionRegistrar(Bean定义的注册器),AspectJAutoProxyRegistrar实现了一个registerBeanDefinitions方法。通过AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);去获取名为AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator"的Bean定义信息;然后帮我们导入AnnotationAwareAspectJAutoProxyCreator这个组件
二,AnnotationAwareAspectJAutoProxyCreator展开调查
1,如图可知,AnnotationAwareAspectJAutoProxyCreator这个类同时具有BeanFactory和BeanPostProcessor属性。点进去这个类,看看他们是怎么实现的,点进去发现AnnotationAwareAspectJAutoProxyCreator这个类本身并没有什么我们想要的,但是他有父类。一直点,找到最后一层父类AbstractAutoProxyCreator。
2通过查看,最终找到如下关系,由于AnnotationAwareAspectJAutoProxyCreator是AbstractAutoProxyCreator的子类,所以就找到AnnotationAwareAspectJAutoProxyCreator和BeanPostProcessor的关系,实现了一个后置处理器的前置方法。然后再找AnnotationAwareAspectJAutoProxyCreator和BeanFactroyAware的关系。AbstractAutoProxyCreator实现了postProcessBeforeInstantiation接口而postProcessBeforeInitialization是开放式接口。用于开发者自己实现
3,通过下面图可知,找到他们之间的关系
4,下面给出一张完整的关系图。
5,接下来就围绕这张关系图去找主要的类,找主要的方法去理清楚AOP的实现过程。由上图可知,一个最主要的类就是AbstractAutoProxyCreator,还有最主要的两个方法也就是那个后置处理器的前置方法和后置方法。postProcessBeforeInstantiation、postProcessAfterInitialization、下面一个一个进行分析。
三,postProcessBeforeInstantiation
一,找事务的增强器。
还记得之前的IOC的那篇文章在执行doCreateBean之前,resolveBeforeInstantiation这个方法将Bean定义信息进行了代理。并且放入了缓存中。postProcessBeforeInstantiation这个方法就是从resolveBeforeInstantiation这里方法里面走进来的。点进postProcessBeforeInstantiation这个方法,Object cacheKey = getCacheKey(beanClass, beanName);进来就去从缓存拿,然后看isInfrastructureClass这个方法,判断的是是不是基础的Bean。什么是基础Bean比如Advice.class\Pointcut.class\Advisor.class等等等。然后还要判断shouldSkip()这个方法应不应该跳过。点进去我们发现有一个这样的findCandidateAdvisors()方法,这个方法就是在找事务的增强器。那么为什么这么说,因为在父类里通过advisorRetrievalHelper(切面查找工具类)这个类的findAdvisorBeans方法可知并没有找到实现了Advisor.class的类。从上图也能看出AnnotationAwareAspectJAutoProxyCreator的类图里面也没有看到跟Advisor.class相关的类或者实现。这个方法是怎么判断的呢?它进来先是从缓存里面去拿,没拿到,紧接着去容器当中去找。BeanFactoryUtils.beanNamesForTypeIncludingAncestors,也没找到,所以直接返回了一个空的List对象。由此可知,我们可以把findCandidateAdvisors()方法理解为在查找事务的增强器。下面给出一张流程图便于理解。
二,寻找我们自己定义的AspectJ
findCandidateAdvisors()这个方法走完以后,没找到关于事务的切面,然后接着往下走this.aspectJAdvisorsBuilder.buildAspectJAdvisors()这段代码点进去,进去发现第一次this.aspectBeanNames获取依然是null,然后如果为空的话,通过BeanFactoryUtils.beanNamesForTypeIncludingAncestors这个东西,把所有的类的名称都捞出来。然后通过for循环你的BeanName去获取你的BeanType,然后判断你的beanType是不是AspectJ。如果 是接着往下走找到getAdvisors方法。第一步获取增强器的类型getAspectMetadata().getAspectClass()。 在获取增强器的名称。再往下看,有一个for循环,里面有一个getAdvisorMethods方法,也就是去循环你的这个方法,点到这个方法里面看一看,然后会发现,通过这个doWithMethods方法,会把你所有的增强器捞出来。并且要排除你的切点(Pointcut.class)。
三, 获取增强器getAdvisors
1首先循环你所有去除切点的增强器方法。没循环一次调用一次getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName)方法。点进getAdvisor方法。接下来找到一个创建切面的实现类InstantiationModelAwarePointcutAdvisorImpl(实例化切面),点进去,这个方法里前面做了一些基础赋值和判断是否是懒加载等校验。下面有个最关键的方法instantiateAdvice(this.declaredPointcut);点进去找到getAdvice方法(获取通知)。在这个方法中找到AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod)这个方法,他是意思是说,在方法上找到所有的切面上的注解。这个方法里会遍历如下图所示的类。如果找到了直接返回到getAdvice这个方法。
2,回到getAdvice方法中可以看到下面有一个switch选择。如下图,通过这switch判断你或取到的注解的类型是什么东东。如果是before就new一个AspectJMethodBeforeAdvice,这个东西就是切面通知。到这里直接就返回到getAdvisors方法中把它放入advisors中去。下面在画一张流程图
3,流程图
3,最终执行完,在buildAspectJAdvisors()方法中把刚才找到的切面都放入切面的缓存中去this.advisorsCache.put(beanName, classAdvisors)和this.aspectFactoryCache.put(beanName, factory);放到这两个缓存里面来。至此shouldSkip()方法执行完毕。最后发现 postProcessBeforeInstantiation这个东西他就是说将我们自己定义切面都给捞出来。并且放入增强器缓存中。
四:postProcessAfterInitialization创建代理对象。
点进去这个方法,也许有人会问这个方法是从哪里进来的。在分析IOC的时候,说到了创建属性的那个方法,在后面进行初始化的时候,执行了一些后置处理器postProcessAfterInitialization 这个方法就是从invokeInitMethods方法中的applyBeanPostProcessorsAfterInitialization方法进来的。
点进去wrapIfNecessary这个方法前面执行了一些判断找到getAdvicesAndAdvisorsForBean这个方法。找Advices类型的和Advisors这个类型,这个方法是找事务和AOP都是通过这个方法。因为事务和AOP的执行流程很相似,事务的流程在后面的文章会进行讲解。那么这个方法到底做了什么呢。看名知意。点进去发现了findEligibleAdvisors这个方法,找到一个合适的增强器。再点进去。看第一行findCandidateAdvisors()又执行了一次,所以里面流程不会走,而是直接从缓存中拿到了增强器。因为在before中我们创建过了。既然找到了那么应该怎么办呢,看下面的方法
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
这个意思就是说找到我本类能用的。比如说你现在有两个切面,当本类是A的时候,那么只能有其中的一个切面对我进行增强的植入,那么另一个可能在切另外一个类,所以这个方法就是找出我奔雷能用的切面。点进去看看。然后找到方法canApply(candidate, clazz, hasIntroductions),意思是能用的。顺便强调一下,我们只看有用的代码边边角角这里不做介绍。点进canApply方法。在其中你会发现有一段advisor instanceof PointcutAdvisor,PointcutAdvisor pca = (PointcutAdvisor) advisor;将获取到的进行转换一下看看是否能用。在点进去canApply,这里面是一个方法的匹配器。通过循环去匹配看看我们能不能用。最后执行完,直接返回到getAdvicesAndAdvisorsForBean这个方法中,这个方法会判断,如果找到空的就不需要代理。如果找到了下一步就通过wrapIfNecessary这个方法中的createProxy来进行代理。
2,createProxy
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);暴露代理对象
意思就是:@EnableAspectJAutoProxy(exposeProxy =true)暴露代理对象
点进createProxy方法,找到buildAdvisors方法点进去,把返回的切面数组放入proxyFactory.最后找到getProxy这个方法点进去,其实这个方法就是真正的去代理的对象.找到createAopProxy这个方法.其中一段targetClass.isInterface() || Proxy.isProxyClass(targetClass)如果是接口,或者Proxy的类就用jdk去代理,否则用Cglib去代理或者强制指定Cglib去代理,否则就用jdk去代理.执行完返回来,找到getProxy方法,Proxy.newProxyInstance(classLoader, proxiedInterfaces,this);真正的去创建代理对象.
五,总结
创建AOP的代理对象主要就是如下几点流程,第一postProcessBeforeInstantiation这个后置处理器就是找到你所有的切面信息.并且放入缓存中去,postProcessAfterInitialization这个后置处理器就是创建我们的代理对象.其中的一些校验,细节,上面也有部分的讲解.AOP(创建代理对象)至此结束,下面附上一张整体的流程图.