接上一回,讲到了getAdvicesAndAdvisorsForBean方法,该方法的目的是获取并生成Advisor Bean。其中包含了扫描经过@Aspect注解配置且与Bean方法的匹配的Advice,也是本章主要讲的内容java
/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } /** * Find all eligible Advisors for auto-proxying this class. * @param beanClass the clazz to find advisors for * @param beanName the name of the currently proxied bean * @return the empty List, not {@code null}, * if there are no pointcuts or interceptors * @see #findCandidateAdvisors * @see #sortAdvisors * @see #extendAdvisors */ protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } ....
关注findEligibleAdvisors方法能够清楚地知道这里主要分四步:spring
什么是Advisor? 首先,Advice是加强方法,即@Around, @Before等注解修饰的方法。而Advisor则是在Advice之上再包了一层。例如PointcutAdvisor则包有Advice和Pointcut
下面接着看findCandidateAdvisors和findAdvisorsThatCanApply缓存
/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java .... /** * Find all candidate Advisors to use in auto-proxying. * @return the List of candidate Advisors */ protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } .... /org/springframework/aop/aspectj/annotation/AnnotationAwareAspectJAutoProxyCreator.java .... @Override protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; } ....
这里findCandidateAdvisors在AbstractAdvisorAutoProxyCreator中有实现,同时被AnnotationAwareAspectJAutoProxyCreator重写了。不过能够看到重写的方法中先调用了super.findCandidateAdvisor,所以两个方法的代码都被执行了。app
/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java .... /** * Look for AspectJ-annotated aspect beans in the current bean factory, * and return to a list of Spring AOP Advisors representing them. * <p>Creates a Spring Advisor for each AspectJ advice method. * @return the list of {@link org.springframework.aop.Advisor} beans * @see #isEligibleBean */ public List<Advisor> buildAspectJAdvisors() { // aspectBeanNames,缓存 // tips: aspectBeanNames由volatile修饰 // volatile: 保证变量可见性,指令不可重排 List<String> aspectNames = this.aspectBeanNames; // 如缓存存在,则跳过初始化步骤 if (aspectNames == null) { // synchronized, 同步锁 // 锁住当前实例,里面的内容同一时间只会被一个线程执行 synchronized (this) { // 拿到锁后再次获取缓存,避免重复初始化 aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // 获取原始类为Object的bean,即全部bean String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { // 是不是合适的bean if (!isEligibleBean(beanName)) { continue; } // We must be careful not to instantiate beans eagerly as in this case they // would be cached by the Spring container but would not have been weaved. Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } // isAspect 是否为@Aspect注解修饰的Bean // 是否是很亲切方法,终于读到它了。这是咱们在第二章一开始就提到的方法。 if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); // 由beanType,beanName组合Metadata,包含了建立Advisor须要的内容 AspectMetadata amd = new AspectMetadata(beanType, beanName); // PerClauseKind.SINGLETON 单例模式 // 由@Aspect中的value参数配置,这个参数Bean的scope 有点相似,用来配置生命 周期,默认都为单例。可配为"每..."的模式 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { // 生成实例工厂类 MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 生成Advisors实例 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); // 若是Aspect Bean是单例,则缓存到advisorsCache if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } // 若是不是,则将工厂缓存到aspectFactoryCache else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // Per target or per this. // bean为单例,@Aspect也要配置为单例 if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } // 跟前一个分支同样,生成Advisors实例,而后将工厂缓存到aspectFactoryCache MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { // 经过aspectName(beanName)获取advisors缓存 List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); // 如已存在,则加载advisorsCache if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } // 如不存在,则加载factoryCache,再从工厂生成advisors,与上面初始时候的两个分支对应 // ps:这里并无作factory的空判断... else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; } ....
因为这段代码比较长,我将过程注释在代码中。其中英文为源码注释。ide
那么,以上即是经过beanName扫描@Aspect配置并生成Advisor的过程了。其中this.advisorFactory.getAdvisors(factory)是生成Advisor类的具体内容。深挖的话还能再写一篇文章,这里就不细说了。有兴趣的能够自行阅读。ui
如今咱们得到了全部的候选Advisor,那么找出和当前Bean匹配的Advisor呢?this
/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java .... /** * Search the given candidate Advisors to find all Advisors that * can apply to the specified bean. * @param candidateAdvisors the candidate Advisors * @param beanClass the target's bean class * @param beanName the target's bean name * @return the List of applicable Advisors * @see ProxyCreationContext#getCurrentProxiedBeanName() */ protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } } ....
一步一步往下探lua
/org/springframework/aop/support/AopUtils.java .... /** * Determine the sublist of the {@code candidateAdvisors} list * that is applicable to the given class. * @param candidateAdvisors the Advisors to evaluate * @param clazz the target class * @return sublist of Advisors that can apply to an object of the given class * (may be the incoming List as-is) */ public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } .... /** * Can the given advisor apply at all on the given class? * This is an important test as it can be used to optimize * out a advisor for a class. * @param advisor the advisor to check * @param targetClass class we're testing * @return whether the pointcut can apply on any method */ public static boolean canApply(Advisor advisor, Class<?> targetClass) { return canApply(advisor, targetClass, false); } /** * Can the given advisor apply at all on the given class? * <p>This is an important test as it can be used to optimize out a advisor for a class. * This version also takes into account introductions (for IntroductionAwareMethodMatchers). * @param advisor the advisor to check * @param targetClass class we're testing * @param hasIntroductions whether or not the advisor chain for this bean includes * any introductions * @return whether the pointcut can apply on any method */ public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } } ....
最后定位到canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)方法线程
/org/springframework/aop/support/AopUtils.java /** * Can the given pointcut apply at all on the given class? * <p>This is an important test as it can be used to optimize * out a pointcut for a class. * @param pc the static or dynamic pointcut to check * @param targetClass the class to test * @param hasIntroductions whether or not the advisor chain * for this bean includes any introductions * @return whether the pointcut can apply on any method */ public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) { return false; } MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... return true; } IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<?>> classes = new LinkedHashSet<>(); if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if (introductionAwareMethodMatcher != null ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) { return true; } } } return false; }
能够看出判断是不是该bean合适的advisor,是经过advisor.getPointcut().getClassFilter().matches(targetClass)方法来判断的。匹配完class之后下面还有MethodMatcher来匹配method。回想咱们在配置pointcut的时候不单单有class的规则,也有method的规则。code
固然,再深刻matches方法进去的话就是pointcut的匹配语法实现了。有兴趣的能够自行阅读。
读到这儿,Spring AOP如何扫描@Aspect配置,生成Advisor类,并匹配对应的Bean整个流程已经很清楚了。这里再总结一下: