我们看到创建代理前首先要获取到Advisor设置给ProxyFactory,之后才可进行代理的创建。那么容器中的Advisor是如何实例化并注册的?
这个最开始的入口是在AbstractAutoProxyCreator的postProcessBeforeInstantiation方法中。
完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把它们结合起来,完成这个作用的就是Advisor(通知器/顾问器)。通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它,也就是说通过Advisor,把Advice和Pointcut结合起来,这个结合为使用IOC容器配置AOP应用,或者说即开即用地使用AOP基础设施,提供了便利。
【1】前置流程
如下图所示,在AbstractApplicationContext的refresh
方法中会触发registerBeanPostProcessors(beanFactory);
进行Bean后置处理器的注册。
而在AbstractAutowireCapableBeanFactory的createBean过程中,会触发resolveBeforeInstantiation(beanName, mbdToUse);,那么这里就会触发applyBeanPostProcessorsBeforeInstantiation。
AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsBeforeInstantiation方法如下所示。
@Nullable protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
这里会判断BeanPostProcessor 是否为InstantiationAwareBeanPostProcessor,如果是,则调用其postProcessBeforeInstantiation方法。
InstantiationAwareBeanPostProcessor是BeanPostProcessor的一个子接口,在bean的属性设置或autowire触发前增加before-instantiation和after-instantiation回调。通常用于抑制特定目标bean的默认实例化,例如创建具有特殊TargetSources的代理(池目标、延迟初始化目标等),或实现其他注入策略,如字段注入。
如下所示是其子类实现,这里我们主要分析AbstractAutoProxyCreator。
如下图所示,AbstractAutoProxyCreator的postProcessBeforeInstantiation会首先对bean进行判断。isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName),前者用来判断是否为基础类,后置用来判断是否需要直接跳过。
当前这只是语义含义,实际上isInfrastructureClass用来判断当前bean是否为Advice、Pointcut、Advisor、AopInfrastructureBean或者(标注了Aspect注解但是bean的field不是以ajc$开头)。
我们看下shouldSkip方法。这里会调用AspectJAwareAdvisorAutoProxyCreator的shouldSkip方法,如下所示。
@Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names List<Advisor> candidateAdvisors = findCandidateAdvisors(); //如果advisor是AspectJPointcutAdvisor 且切面名称是beanName则跳过 for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); } //super.shouldSkip(beanClass, beanName); AbstractAutoProxyCreator#shouldSkip protected boolean shouldSkip(Class<?> beanClass, String beanName) { //是否为 original instance return AutoProxyUtils.isOriginalInstance(beanName, beanClass); }
很显然,advisor就是从findCandidateAdvisors方法得到的。
【2】得到Advisor
结合前面流程,这里会走到AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法。也就说这个方法才是真正获取(实例化)Advisor的方法。
同样,在Spring AOP中如何为Bean创建代理?一文中为Bean创建代理获取Advisor时也会触发该方法。
@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; } this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
首先调用父类的findCandidateAdvisors方法,然后使用BeanFactoryAspectJAdvisorsBuilderAdapter创建AspectJAdvisor。
① super.findCandidateAdvisors();
这里是AbstractAdvisorAutoProxyCreator的findCandidateAdvisors方法。
//AbstractAdvisorAutoProxyCreator#findCandidateAdvisors protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } // advisorRetrievalHelper是BeanFactoryAdvisorRetrievalHelperAdapter;
我们跟踪看一下advisorRetrievalHelper是如何找到Advisor的。
public List<Advisor> 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! // 尝试获取Advisor 如internalTransactionAdvisor advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<>(); } List<Advisor> advisors = new ArrayList<>(); for (String name : advisorNames) { // 这里默认返回true if (isEligibleBean(name)) { // 如果是正在创建的,则跳过 if (this.beanFactory.isCurrentlyInCreation(name)) { if (logger.isTraceEnabled()) { logger.trace("Skipping currently created advisor '" + name + "'"); } } else { try { // 从容器中获取Bean advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); // .... throw ex; } } } } return advisors; }
总结来讲该方法就是从容器中找Advisor,如果正在创建则跳过否则就获取到然后返回。
② aspectJAdvisorsBuilder.buildAspectJAdvisors
BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法如下所示。我们的切片被包装成Advisor就是在这里实现的。
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // 获取到所有的Bean,本文这里有460个 String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { //AnnotationAwareAspectJAutoProxyCreator.isEligibleAspectBean进行判断,默认返回true 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; } // 如果当前Bean标注了Aspect注解 且未被ajc编译 if (this.advisorFactory.isAspect(beanType)) { // 放到aspectNames中-包含单例和非单例 aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); // 默认就是SINGLETON if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { // 如果是单例则放入缓存 this.advisorsCache.put(beanName, classAdvisors); } else { // 否则放入aspectFactoryCache this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // Per target or per this. 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)); } } } // 重新给aspectBeanNames 赋值 this.aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { //这里获取的是单例的 List<Advisor> 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; }
这里大概分为三种情况:
如果List aspectNames为null,则进行初始化;
如果List aspectNames为空,则直接返回空列表;
否则则尝试从advisorsCache或者advisorFactory获取advisors
那么在第一次是一定为null的,这里会从容器中获取到(标注了Aspect注解 且未被ajc编译的bean),如我们自己定义的logAspect。最终会通过this.advisorFactory.getAdvisors(factory)得到Advisor。
那么这里List classAdvisors = this.advisorFactory.getAdvisors(factory);就是核心部分。
③ ReflectiveAspectJAdvisorFactory.getAdvisors
@Override public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { // 得到切片类型与名称 Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); //进行校验 PerClauseKind.PERCFLOW PerClauseKind.PERCFLOWBELOW 是否有注解Aspect validate(aspectClass); // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator // so that it will only instantiate once. // 进行包装,使其只能实例化一次 MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List<Advisor> advisors = new ArrayList<>(); // 得到AdvisorMethod,即不包含Pointcut的方法 for (Method method : getAdvisorMethods(aspectClass)) { // 得到Advisor Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor != null) { advisors.add(advisor); } } // If it's a per target aspect, emit the dummy instantiating aspect. // PerClauseKind.PERTARGET PerClauseKind.PERTHIS PerClauseKind.PERTYPEWITHIN才会进入 if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // Find introduction fields. // 引入通知中,尝试将每一个Field 包装为一个Advisor for (Field field : aspectClass.getDeclaredFields()) { // 这里针对的是DeclareParents 会创建DeclareParentsAdvisor Advisor advisor = getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } } return advisors; }
如上代码所示,这里首先获取切面类中未标注Pointcut注解的方法,然后实例化得到InstantiationModelAwarePointcutAdvisorImpl这样一个Advisor。
然后判断aspect是否需要懒加载,如果是则实例化SyntheticInstantiationAdvisor放入advisors的第一个位置。
最后对引入通知进行处理,拿到那些标注了DeclareParents 注解的filed,得到相应的DeclareParentsAdvisor放入advisors。
至此就完成了advisors 的查找。我们可以跟踪看一下getAdvisor和getDeclareParentsAdvisor方法。
getAdvisor
如下所示,首先进行校验然后获取AspectJExpressionPointcut ,如果不为null则实例化InstantiationModelAwarePointcutAdvisorImpl。
@Nullable public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }
在实例化InstantiationModelAwarePointcutAdvisorImpl,还会对Advice进行实例化。如下所示在ReflectiveAspectJAdvisorFactory的方法中会拿到方法的AspectJAnnotation,根据其AnnotationType分别创建Advice。
// ReflectiveAspectJAdvisorFactory#getAdvice @Override @Nullable public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); // 获取方法上的注解 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // If we get here, we know we have an AspectJ method. // Check that it's an AspectJ-annotated class if (!isAspect(candidateAspectClass)) { throw new AopConfigException("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]"); } if (logger.isDebugEnabled()) { logger.debug("Found AspectJ method: " + candidateAdviceMethod); } AbstractAspectJAdvice springAdvice; // 根据注解的类型创建对应的Advice switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; case AtAround: springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; default: throw new UnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); } // Now to configure the advice... springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }
AnnotationType | Advice |
AtPointcut | null |
AtAround | AspectJAroundAdvice |
AtBefore | AspectJMethodBeforeAdvice |
AtAfter | AspectJAfterAdvice |
AtAfterReturning | AspectJAfterReturningAdvice |
AtAfterThrowing | AspectJAfterThrowingAdvice |
到这里,我们自定义的logAspect如何成为一个Advisor就清晰了。我们再看一下getDeclareParentsAdvisor。
getDeclareParentsAdvisor
这里主要为引入通知解析Advisor 。
@Nullable private Advisor getDeclareParentsAdvisor(Field introductionField) { // 判断DeclareParents注解 DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class); if (declareParents == null) { // Not an introduction field return null; } // 判断默认实现 if (DeclareParents.class == declareParents.defaultImpl()) { throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents"); } // 实例化DeclareParentsAdvisor return new DeclareParentsAdvisor( introductionField.getType(), declareParents.value(), declareParents.defaultImpl()); }
【3】如果同时有引入通知呢?
如下所示在切面中添加了引入通知:
@Aspect @Component public class LogAspect { @DeclareParents(value = "com.recommend.controller.HomeController",defaultImpl=MyDeclareImpl.class) private MyDeclareService myDeclareService; //... }
此时我们获取得到排序的eligibleAdvisors如下所示,DeclareParentsAdvisor排在了第二位。
0 = {ExposeInvocationInterceptor$1@7173} "org.springframework.aop.interceptor.ExposeInvocationInterceptor.ADVISOR" 1 = {DeclareParentsAdvisor@7137} 2 = {InstantiationModelAwarePointcutAdvisorImpl@7136} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public void com.recommend.config.LogAspect.AfterThrowing(org.aspectj.lang.JoinPoint,java.lang.Exception)]; perClauseKind=SINGLETON" 3 = {InstantiationModelAwarePointcutAdvisorImpl@7135} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public void com.recommend.config.LogAspect.AfterReturning(org.aspectj.lang.JoinPoint,java.lang.Object)]; perClauseKind=SINGLETON" 4 = {InstantiationModelAwarePointcutAdvisorImpl@7134} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public void com.recommend.config.LogAspect.afterMethod(org.aspectj.lang.JoinPoint)]; perClauseKind=SINGLETON" 5 = {InstantiationModelAwarePointcutAdvisorImpl@7132} "InstantiationModelAwarePointcutAdvisor: expression [logPointCut()]; advice method [public java.lang.Object com.recommend.config.LogAspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; perClauseKind=SINGLETON" 6 = {InstantiationModelAwarePointcutAdvisorImpl@7133} "InstantiationModelAwarePointcutAdvisor: expression [execution(* com.recommend.controller.*.*(..))]; advice method [public void com.recommend.config.LogAspect.beforeMethod(org.aspectj.lang.JoinPoint)]; perClauseKind=SINGLETON"
DeclareParentsAdvisor对象如下所示: