33--SpringAop获取增强(一)

引 上一节分析了aspectj-autoproxy标签的解析过程,并注册了AnnotationAwareAspectJAutoProxyCreator。但是该类的作用是什么呢,看起来茫然无措,这时不妨查看一下类的继承关系结构。
33--SpringAop获取增强(一)
文章图片
AnnotationAwareAspectJAutoProxyCreator类图结构 从上图可以看到,AnnotationAwareAspectJAutoProxyCreator类实现了BeanPostProcessor接口,读过之前的章节或者对bean的生命周期有所了解的同学一定知道,在bean实例化完成之前和完成之后分别会自动BeanPostProcessor接口的postProcessBeforeInitialization和postProcessAfterInitialization方法。
【33--SpringAop获取增强(一)】依次打开AnnotationAwareAspectJAutoProxyCreator的父类,在AbstractAutoProxyCreator类里,找到postProcessBeforeInitialization方法和postProcessAfterInitialization方法,开始分析。
1. postProcessBeforeInstantiation方法

public Object postProcessBeforeInstantiation(Class beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); // 1、预处理判断 if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { // 判断该类是否应被处理过 if (this.advisedBeans.containsKey(cacheKey)) { return null; } // 判断beanClass是否需要被代理 // isInfrastructureClass-->判断beanClass是否为AOP基础类例如Advice(增强),Advisors(切面),Pointcut(切点) // shouldSkip-->判断beanClass是否指定了不需要代理 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { // 缓存找到的切面类信息 this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } }// Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. // 2、如果有自定义TargetSource的话,则在此创建代理 /** *自定义TargetSource示例: * ** * * * * */ TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }

postProcessBeforeInstantiation一共做了两件事情
  1. 缓存切面类的信息
    先判断对应的beanClass是否为Aop的基础类,如果是的话,直接缓存。
    然后通过shouldSkip方法判断beanClass是否需要被自动代理,如果不需要被自动代理的话,返回true,否则返回false。
  2. 判断有无自定义TargetSource,如果有的话,则在此方法里创建代理
    关于自定义TargetSource已经给出了一个简单的实例,感兴趣的同学可以自己debug代码。
其中第一步的shouldSkip(beanClass, beanName)方法,看似简单,其实这里面包含了非常复杂的业务逻辑处理。·即增强的提取
2. shouldSkip方法简析
/** * 如果给定的bean不应该被认为是后处理器自动代理的,子类应该重写这个方法以返回true。 * @param beanClass the class of the bean * @param beanName the name of the bean * @return */ @Override protected boolean shouldSkip(Class beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names // 1、查找所有候选增强 List candidateAdvisors = findCandidateAdvisors(); // 2、循环判断所有的增强,如果增强是AspectJPointcutAdvisor的实例 //并且其名称与当前bean的名称相同,则返回true,即该bean无需代理 for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); }

该方法主逻辑很简单,查找所有的候选增强并循环判断当前beanName是否需要被代理,关键是findCandidateAdvisors()方法中获取增强的过程。
/** * AnnotationAwareAspectJAutoProxyCreator * 查找所有候选增强方法 * @return */ @Override protected List findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. // 1、从父类中获取所有的增强 List advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. // 2、从当前BeanFactory中查找所有标记了@AspectJ的注解的bean,并返回增强注解集合 if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }

该方法也非常简单:
  • 从父类中获取所有的增强
  • 从当前BeanFactory中查找所有标记了@AspectJ的注解的bean,并返回增强注解集合
    逐个对其进行分析:
3. findCandidateAdvisors方法分析
protected List findCandidateAdvisors() { return this.advisorRetrievalHelper.findAdvisorBeans(); }

/** * 从当前BeanFactory中寻找所有的增强bean,忽略FactoryBean和正在创建的bean * Find all eligible Advisor beans in the current bean factory, * ignoring FactoryBeans and excluding beans that are currently in creation. * @return the list of {@link org.springframework.aop.Advisor} beans * @see #isEligibleBean */ public List findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. // 获取缓存的增强 String[] advisorNames = this.cachedAdvisorBeanNames; // 缓存增强为空,则重新查找增强并缓存 if (advisorNames == null) { // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the auto-proxy creator apply to them! // 从当前BeanFactory中获取所有类型为Advisor的bean advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } // 当前BeanFactory中没有类型为Advisor的bean则返回一个空的集合 if (advisorNames.length == 0) { return new ArrayList<>(); }// 循环所有获取到的bean List advisors = new ArrayList<>(); for (String name : advisorNames) { if (isEligibleBean(name)) { // 跳过正在创建的增强 if (this.beanFactory.isCurrentlyInCreation(name)) { if (logger.isDebugEnabled()) { logger.debug("Skipping currently created advisor '" + name + "'"); } } else { try { // 通过getBean方法获取bean实例 advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; String bceBeanName = bce.getBeanName(); if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { // 跳过正在创建的增强 if (logger.isDebugEnabled()) { logger.debug("Skipping advisor '" + name + "' with dependency on currently created bean: " + ex.getMessage()); } // Ignore: indicates a reference back to the bean we're trying to advise. // We want to find advisors other than the currently created bean itself. continue; } } throw ex; } } } } return advisors; }

4. buildAspectJAdvisors方法分析
/** * 在当前BeanFactory中查找AspectJ-annotated的注解信息,并返回增强集合 * Look for AspectJ-annotated aspect beans in the current bean factory, * and return to a list of Spring AOP Advisors representing them. * Creates a Spring Advisor for each AspectJ advice method. * @return the list of {@link org.springframework.aop.Advisor} beans * @see #isEligibleBean */ public List buildAspectJAdvisors() { List aspectNames = this.aspectBeanNames; // 1、提取增强 if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // 1.1、获取容器中的所有bean String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); // 1.2、循环所有的bean,并从切面类上提取增强 for (String beanName : beanNames) {// 判断该beanName是否符合条件 // 如果配置文件指定了属性,那么只有符合表达式条件的切面类的增强才会被提取 // 例如:配置 // 那么只有dogAspect切面类的增强才会被提取 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. // 获取beanType类型 Class beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } // 如果beanType是一个切面类 if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); /** * 切面实例化模型简介 * * singleton: 即切面只会有一个实例; * perthis: 每个切入点表达式匹配的连接点对应的AOP对象都会创建一个新切面实例; *使用@Aspect("perthis(切入点表达式)")指定切入点表达式; *例如: @Aspect("perthis(this(com.lyc.cn.v2.day04.aspectj.Dog))") * pertarget: 每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例; *使用@Aspect("pertarget(切入点表达式)")指定切入点表达式; *例如: * * 默认是singleton实例化模型,Schema风格只支持singleton实例化模型,而@AspectJ风格支持这三种实例化模型。 */ // singleton实例化模型处理 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 获取所有的增强方法,并缓存 List classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } // perthis或pertarget实例化模型处理 else { /** * 注意:当使用perthis或pertarget属性时,切面类不能是单例bean,否则会抛出下面的异常 * 例如: * 则会报错,应该为 * */ if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } }// 2、返回从缓存中获取提取到的增强方法 if (aspectNames.isEmpty()) { return Collections.emptyList(); } List advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; }

其中的步骤在代码里都标注的很清晰了,这里会涉及到一个切面实例化模型的概念,如果初看AOP的源码,完全可以忽略该概念,把精力放在主线的分析上。其实该方法里大部分都是预处理、缓存、以及各种业务判断,增强的提取工作交给了List classAdvisors = this.advisorFactory.getAdvisors(factory); 。这也是我们要分析的重点。

    推荐阅读