AbstractAdvisorAutoProxyCreator 这是另一类自动代理方式
它是Spring2.0提供的(2.0版本2006年才发布哦~~~)
顾名思义,它和Advisor有关(只有被切入的类,才会给它创建一个代理类),它的核心方法是实现了父类的:getAdvicesAndAdvisorsForBean来获取Advisor们
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator { // 这个类是重点,后面会详细介绍 @Nullable private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper; // 重写了setBeanFactory方法,事需要保证bean工厂必须是ConfigurableListableBeanFactory @Override public void setBeanFactory(BeanFactory beanFactory) { super.setBeanFactory(beanFactory); if (!(beanFactory instanceof ConfigurableListableBeanFactory)) { throw new IllegalArgumentException( "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory); } // 就这一句话:this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory) // 对Helper进行初始化,找advisor最终事委托给他了的 // BeanFactoryAdvisorRetrievalHelperAdapter继承自BeanFactoryAdvisorRetrievalHelper,为私有内部类,主要重写了isEligibleBean()方法,调用.this.isEligibleAdvisorBean(beanName)方法 initBeanFactory((ConfigurableListableBeanFactory) beanFactory); } // 这是复写父类的方法,也是实现代理方式。找到作用在这个Bean里面的切点方法 // 当然 最终最终事委托给BeanFactoryAdvisorRetrievalHelper去做的 @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { // findEligibleAdvisors:显然这个是具体的实现方法了。 // eligible:合格的 合适的 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } // 找出合适的Advisor们~~~ 主要分了下面几步 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 首先找出所有的候选的Advisors,(根据名字判断)实现见下面~~~~ List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 对上面找到的候选的Advisors们,进行过滤操作~~~ 看看Advisor能否被用在Bean上(根据Advisor的PointCut判断) // 主要依赖于AopUtils.findAdvisorsThatCanApply()方法 在工具类讲解中有详细分析的 // 逻辑简单概述为:看目标类是不是符合代理对象的条件,如果符合就把Advisor加到集合中,最后返回集合 // 简单的说:它就是会根据ClassFilter和MethodMatcher等等各种匹配。(但凡只有有一个方法被匹配上了,就会给他创建代理类了) // 方法用的ReflectionUtils.getAllDeclaredMethods,**因此哪怕是私有方法,匹配上都会给创建的代理对象,这点务必要特别特别的注意** List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); //提供一个钩子。子类可以复写此方法 然后对eligibleAdvisors进行处理(增加/删除/修改等等) // AspectJAwareAdvisorAutoProxyCreator提供了实现 extendAdvisors(eligibleAdvisors); // 如果最终还有,那就排序吧 if (!eligibleAdvisors.isEmpty()) { // 默认排序方式:AnnotationAwareOrderComparator.sort()排序 这个排序和Order接口有关~~~ // 但是子类:AspectJAwareAdvisorAutoProxyCreator有复写此排序方法,需要特别注意~~~ eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } // 找到候选的Advisor们~~~~ 抽象类自己的实现,是直接把这件事委托给了advisorRetrievalHelper // 关于它的具体逻辑 后文问详细分析 毕竟属于核心逻辑 // AnnotationAwareAspectJAutoProxyCreator对它有复写 protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } // 判断给定的BeanName这个Bean,是否是合格的(BeanFactoryAdvisorRetrievalHelper里会用到这个属性) // 其中:DefaultAdvisorAutoProxyCreator和InfrastructureAdvisorAutoProxyCreator有复写 protected boolean isEligibleAdvisorBean(String beanName) { return true; } // 此处复写了父类的方法,返回true了,表示 @Override protected boolean advisorsPreFiltered() { return true; } }
我们发现这个抽象类主要是提供getAdvicesAndAdvisorsForBean()这个方法的获取模版(虽然它没有提供抽象方法给子类去实现,但子类复写了protected方法,改变了一些默认行为。但是各个实现类都各有不同,现在我们看看实现:)
从简单到复杂,从不用到常用,现在分析分析这些实现类:
DefaultAdvisorAutoProxyCreator
打个比方:它就是BeanNameAutoProxyCreator的加强版。如果说BeanNameAutoProxyCreator就是步枪需要自己装配,DefaultAdvisorAutoProxyCreator就是自动步枪了,Spring可以完成自动匹配的工作了
一般,我们只需要这样配置即可
@Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { return new DefaultAdvisorAutoProxyCreator(); } // 还需要对应的Advisor(可以有多个~~) 从而给能够匹配上的创建代理对象了 @Bean public NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor() { NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor = new NameMatchMethodPointcutAdvisor(); //拦截到了HelloService#hello()方法,因此会给他创建代理对象 nameMatchMethodPointcutAdvisor.addMethodName("*hello"); // 请注意:此处虽然HelloController有个方法名叫helloGet,但是不会创建代理得。因为这在根容器里,这种情况不作用与子容器的Bean的 nameMatchMethodPointcutAdvisor.addMethodName("helloGet"); nameMatchMethodPointcutAdvisor.setAdvice(new MyMethodInteceptor()); return nameMatchMethodPointcutAdvisor; }
这样它就会自动的去把Advisor匹配上的Bean进行代理掉。(不像BeanNameAutoProxyCreator还得手动指定BeanName,以及拦截器们)
一般都需要自己像容器注入自己的Advisor,比如NameMatchMethodPointcutAdvisor,否则它也不知道去代理谁嘛。只有被对应的Advisor匹配上的才会生成代理对象
它的源码很简单:它也是只复写了一个方法
// Consider {@code Advisor} beans with the specified prefix as eligible, if activated. // 用到了前缀之类的。主要是考虑可以通过前缀匹配某一类Bean,而其他的Advisor我就不匹配了 // 前缀的作用:进行分离匹配(而不是拿所有的Advisor~~) @Override protected boolean isEligibleAdvisorBean(String beanName) { if (!isUsePrefix()) { return true; } String prefix = getAdvisorBeanNamePrefix(); return (prefix != null && beanName.startsWith(prefix)); }
InfrastructureAdvisorAutoProxyCreator
Infrastructure:基础设施、基建
听这名字就知道,这是Spring给自己内部使用的一个自动代理创建器。这个类在@EnableTransactionManagement事务相关里会再次提到(它的AutoProxyRegistrar就是向容器注册了它),其实它的作用非常简单:主要是读取Advisor类,并对符合的bean进行二次代理
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { ... // 没有其余多余代码 就这一个 // bean工厂含有这个Bean,且这个Bean的Role是BeanDefinition.ROLE_INFRASTRUCTURE 系统内部用的 才返回true @Override protected boolean isEligibleAdvisorBean(String beanName) { return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE); } }
接下来两个实现就和AspectJ相关了~~~相对来说比较难啃一点
AspectJAwareAdvisorAutoProxyCreator
顾名思义,该类主要来处理AspectJ切面的。这也是当下最流行,也是功能最为强大的一种方式吧~~~
它对父类,做了如下几点扩展:
// @since 2.0 public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { // 默认的排序器,它就不是根据Order来了,而是根据@Afeter @Before类似的标注来排序 private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator(); // 核心逻辑:它重写了排序 // 这个排序和`org.aspectj.util`提供的PartialOrder和PartialComparable有关 具体不详叙了 // 这块排序算法还是比较复杂的,控制着最终的执行顺序~ protected List<Advisor> sortAdvisors(List<Advisor> advisors) { ... } // 这个就是对已有的Advisor做了一个扩展: // AspectJProxyUtils这个工具类只有这一个方法 (其实每次addAspect()的时候,都会调用此方法) // Capable:能干的 有才华的 // 它的作用:(若存在AspectJ的Advice),就会在advisors的第一个位置加入`ExposeInvocationInterceptor.ADVISOR`这个advisor @Override protected void extendAdvisors(List<Advisor> candidateAdvisors) { AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); } // 这个相当于: @Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 这个相当于AspectJPointcutAdvisor的子类不要拦截、AspectJ切面自己自己的所有方法不要去拦截。。。 for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } // 父类返回的false return super.shouldSkip(beanClass, beanName); } ... }
ExposeInvocationInterceptor 的作用是用于暴露 MethodInvocation 对象到 ThreadLocal 中,其名字也体现出了这一点。如果其他地方需要当前的 MethodInvocation 对象,直接通过调用静态方法 ExposeInvocationInterceptor.currentInvocation 方法取出。那哪些地方会用到呢????
AspectJExpressionPointcut#matches就有用到~~
AnnotationAwareAspectJAutoProxyCreator
首先AnnotationAwareAspectJAutoProxyCreator它是AspectJAwareAdvisorAutoProxyCreator的子类。
然后从名字中可议看出,它和注解有关。因此其实我们的@EnableAspectJAutoProxy它导入的就是这个自动代理创建器去帮我们创建和AspectJ相关的代理对象的。这也是我们当下使用最为广泛的方式~
// @since 2.0 public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { @Nullable private List<Pattern> includePatterns; //唯一实现类:ReflectiveAspectJAdvisorFactory // 作用:基于@Aspect时,创建Spring AOP的Advice // 里面会对标注这些注解Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的方法进行排序 // 然后把他们都变成Advisor( getAdvisors()方法 ) @Nullable private AspectJAdvisorFactory aspectJAdvisorFactory; //该工具类用来从bean容器,也就是BeanFactory中获取所有使用了@AspectJ注解的bean //就是这个方法:aspectJAdvisorsBuilder.buildAspectJAdvisors() @Nullable private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder; // 很显然,它还支持我们自定义一个正则的模版 // isEligibleAspectBean()该方法使用此模版,从而决定使用哪些Advisor public void setIncludePatterns(List<String> patterns) { this.includePatterns = new ArrayList<>(patterns.size()); for (String patternText : patterns) { this.includePatterns.add(Pattern.compile(patternText)); } } // 可以自己实现一个AspectJAdvisorFactory 否则用默认的ReflectiveAspectJAdvisorFactory public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) { Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null"); this.aspectJAdvisorFactory = aspectJAdvisorFactory; } // 此处一定要记得调用:super.initBeanFactory(beanFactory); @Override protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.initBeanFactory(beanFactory); if (this.aspectJAdvisorFactory == null) { this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory); } this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory); } // 拿到所有的候选的advisor们。请注意:这里没有先调用了父类的super.findCandidateAdvisors() 去容器里找出来一些 // 然后,然后自己又通过aspectJAdvisorsBuilder.buildAspectJAdvisors() 解析@Aspect的方法得到一些Advisor @Override protected List<Advisor> findCandidateAdvisors() { List<Advisor> advisors = super.findCandidateAdvisors(); if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; } // 加了中类型 如果该Bean自己本身就是一个@Aspect, 那也认为是基础主键,不要切了 @Override protected boolean isInfrastructureClass(Class<?> beanClass) { return (super.isInfrastructureClass(beanClass) || (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass))); } // 拿传入的正则模版进行匹配(没传就返回true,所有的Advisor都会生效) protected boolean isEligibleAspectBean(String beanName) { if (this.includePatterns == null) { return true; } else { for (Pattern pattern : this.includePatterns) { if (pattern.matcher(beanName).matches()) { return true; } } return false; } } ... }
AspectJAwareAdvisorAutoProxyCreator它用于xml配置版的AspectJ切面自动代理创建(<aop:config/>)
AnnotationAwareAspectJAutoProxyCreator用于基于注解的自动代理创建(<aop:aspectj-autoproxy/> 或 @EnableAspectJAutoProxy)
BeanFactoryAdvisorRetrievalHelper:从Bean工厂检索出Advisor们
这个类很重要,是真正去容器中找出所有的Advisor的类
// @since 2.0.2 public class BeanFactoryAdvisorRetrievalHelper { private final ConfigurableListableBeanFactory beanFactory; // 本地会做一个简单的字段缓存 @Nullable private String[] cachedAdvisorBeanNames; ... // 这里显然就是核心方法了 public List<Advisor> findAdvisorBeans() { String[] advisorNames = null; synchronized (this) { advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { // 这里不会实例化FactoryBeans // 我们需要保留所有常规bean未初始化以允许自动代理创建者应用于它们 // 注意此处:连祖先容器里面的Bean都会拿出来 (这个方法平时我们也可以使用) advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } } // 如果容器里面没有任何的advisor 那就拉倒吧 if (advisorNames.length == 0) { return new LinkedList<>(); } List<Advisor> advisors = new LinkedList<>(); for (String name : advisorNames) { // isEligibleBean:表示这个bean是否是合格的,默认是true // 但上面书说了InfrastructureAdvisorAutoProxyCreator和DefaultAdvisorAutoProxyCreator都做了对应的复写 if (isEligibleBean(name)) { // 如果当前Bean正在创建中 那好 就啥也不做吧 if (this.beanFactory.isCurrentlyInCreation(name)) { if (logger.isDebugEnabled()) { logger.debug("Skipping currently created advisor '" + name + "'"); } } // 否则就把这个Advisor加入到List里面,是个合法的 else { try { advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { ... continue; } } } } return advisors; } protected boolean isEligibleBean(String beanName) { return true; } }
综上,整个Spring AOP中的自动代理创建器就全部介绍完了,相信收货不小吧~~~
不同的实现类都有自己不同的使用场景。但是在注解驱动大行其道的今天,显然AnnotationAwareAspectJAutoProxyCreator这个自动代理创建器是最流行、也是功能最强大、也是最实用的,所以是我们最应该掌握的~~~
总结
总的来说:Spring的知识是个体系,很多都是环环相扣的。学知识和建楼一样,需要从根基开始,否则永远只能是半桶水,容易洒出来
最后,只给使用的时候两个不成熟的小建议吧:
1.SpringAOP应尽量避免自己创建AutoProxyCreator
2.避免使用低级别的AOP API
比如如下情况(我们自己注册一个创建器):
<bean class="org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator"> <property name="proxyTargetClass" value="true"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/>
最终我却发现走的依旧是JDK动态代理,不是CGLIB。但是如果我这样:
<aop:aspectj-autoproxy proxy-target-class="true"/> <tx:annotation-driven transaction-manager="transactionManager"/>
就一切正常,走的CGLIB
了。至于什么原因,一语道不明,建议还是多看我博文掌握来龙去脉吧(哈哈~~~),读者可以自己思考咯~