Spring AOP(三) Advisor类架构
2021-04-19 23:10
776 查看
Spring AOP是Spring的两大基石之一,不了解其基础概念的同学可以查看这两篇文章AOP基本概念和修饰者模式和JDK Proxy。
如果从代码执行角度来看,Spring AOP的执行过程分为四大步骤:
- 步骤一:Spring框架生成Advisor实例,可以是
@Aspect
,@Async
等注解生成的实例,也可以是程序员自定义的AbstractAdvisor
子类的实例。 - 步骤二:Spring框架在目标实例初始化完成后,也就是使用
BeanPostProcessor
的postProcessAfterInitialization
方法,根据Advisor实例中切入点Pointcut
的定义,选择出适合该目标对象的Advisor实例。 - 步骤三:Spring框架根据Advisor实例生成代理对象。
- 步骤四:调用方法执行过程时,Spring框架执行Advisor实例的通知
Advice
逻辑。
由于这四个步骤涉及的源码量较大,一篇文章无法直接完全讲解完,本篇文章只讲解第一步
Advisor实例生成的源码分析。接下来的文章我们就依次讲解一下后续步骤中比较关键的逻辑。
Advisor类架构
Spring中有大量的机制都是通过AOP实现的,比如说
@Async的异步调用和
@Transational。此外,用户也可以使用
@Aspect注解定义切面或者直接继承
AbstractPointcutAdvisor来提供切面逻辑。上述这些情况下,AOP都会生成对应的Advisor实例。
我们先来看一下Advisor的相关类图。首先看一下
org.aopalliance包下的类图。aopalliance是AOP组织下的公用包,用于AOP中方法增强和调用,相当于一个jsr标准,只有接口和异常,在AspectJ、Spring等AOP框架中使用。
aopalliance定义了AOP的通知
Advice和连接点
Joinpoint接口,并且还有继承上述接口的
MethodInterceptor和
MethodInvocation。这两个类相信大家都很熟悉。
然后我们来看一下Spring AOP中Advisor相关的类图。Advisor是Spring AOP独有的概念,比较重要的类有
AbstractPointcutAdvisor和
InstantiationModelAwarePointcutAdvisor。相关的讲解都在图中表明了,如果这张图中的概念和类同学们都熟识,那么对AOP的了解就已经很深入了。
获取所有Advisor
实例
AOP生成Advisor实例的函数入口是
AbstractAdvisorAutoProxyCreator的
findCandidateAdvisors函数。
// AbstractAdvisorAutoProxyCreator.java 找出当前所有的Advisor protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } // AnnotationAwareAspectJAutoProxyCreator,是AbstractAdvisorAutoProxyCreator的子类 @Override protected List<Advisor> findCandidateAdvisors() { // 调用父类的findCandidateAdvisor函数,一般找出普通的直接 // 继承Advisor接口的实例,比如说`@Async`所需的`AsyncAnnotationAdvisor` List<Advisor> advisors = super.findCandidateAdvisors(); // 为AspectJ的切面构造Advisor,也就是说处理@Aspect修饰的类,生成上文中说的`InstantiationModelAwarePointcutAdvisor`实例 if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
相关的ProxyCreator也有一个类体系,不过太过繁杂,而且重要性不大,我们就先略过,直接将具体的类。由上边代码可知
AbstractAdvisorAutoProxyCreator的
findCandidateAdvisors函数是直接获取Spring容器中的
Advisor实例,比如说
AsyncAnnotationAdvisor实例,或者说我们自定义的
AbstractPointcutAdvisor的子类实例。
AdvisorRetrievalHelper的
findAdvisorBeans函数通过
BeanFactory的
getBean获取了所有类型为
Advisor的实例。
而
AnnotationAwareAspectJAutoProxyCreator看其类名就可知,是与AspectJ相关的创建器,用来获取
@Aspect定义的Advisor实例,也就是
InstantiationModelAwarePointcutAdvisor实例。
接下去我们看一下
BeanFactoryAspectJAdvisorsBuilder的
buildAspectJAdvisors函数,它根据
@Aspect修饰的切面实例生成对应的
Advisor实例。
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; // 第一次初始化,synchronized加双次判断,和经典单例模式的写法一样。 if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { // Spring源码并没有buildAspectJAdvisorsFirstly函数,为了方便理解添加。 // 获取aspectNames,创建Advisor实例,并且存入aspectFactoryCache缓存 return buildAspectJAdvisorsFirstly(); } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList<>(); // 遍历aspectNames,依次获取对应的Advisor实例,或者是MetadataAwareAspectInstanceFactory生成的Advisor实例 for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); // cache可以取到实例,该Advisor是单例的 if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { // 取得Advisor对应的工厂类实例,再次生成Advisor实例,该Advisor是多实例的。 MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; }
buildAspectJAdvisors函数执行时分为两种情况,第一个未初始化时,也就是
aspectNames为null时,执行
buildAspectJAdvisorsFirstly进行第一次初始化,在这一过程中生成切面名称列表
aspectBeanNames和要返回的
Advisor列表,并且将生成的
Advisor实例放置到
advisorsCache中。
第二种情况则是已经初始化后再次调用,遍历
aspectNames,从
advisorsCache取出对应的
Advisor实例,或者从
advisorsCache取出Advisor对应的工厂类对象,再次生成
Advisor实例。
public List<Advisor> buildAspectJAdvisorsFirstly() { List<Advisor> advisors = new ArrayList<>(); List<String> aspectNames = new ArrayList<>(); // 调用BeanFactoryUtils获取所有bean的名称 String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue; } // 获取对应名称的bean实例 Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } /** * AbstractAspectJAdvisorFactory类的isAspect函数来判断是否为切面实例 * 判断条件为是否被@Aspect修饰或者是由AspectJ编程而来。 */ if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); // 切面的属性为单例模式 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 获取一个切面中所有定义的Advisor实例。一个切面可以定义多个Advisor。 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); // 单例模式,只需要将生成的Advisor添加到缓存 if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } // 多实例模式,需要保存工厂类,便于下一次再次生成Advisor实例。 else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; }
buildAspectJAdvisorsFirstly函数的逻辑如下:
- 首先使用
BeanFactoryUtils
获取了BeanFactory中所有的BeanName,然后进而使用BeanFactory
获取所有的Bean实例。 - 遍历Bean实例,通过
ReflectiveAspectJAdvisorFactory
的isAspect
函数判断该实例是否为切面实例,也就是被@Aspect
注解修饰的实例。 - 如果是,则使用
ReflectiveAspectJAdvisorFactory
,根据切面实例的定义来生成对应的多个Advisor
实例,并且将其加入到advisorsCache
中。
生成InstantiationModelAwarePointcutAdvisorImpl实例
ReflectiveAspectJAdvisorFactory的
getAdvisors函数会获取
@Aspect修饰的实例中所有没有被
@Pointcut修饰的方法,然后调用
getAdvisor函数,并且将这些方法作为参数。
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; } // 生成Advisor实例 return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); } private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { // 获得该函数上@Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing注解的信息 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); // 没有上述注解,则直接返回 if (aspectJAnnotation == null) { return null; } AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]); // 获得注解信息中的切入点判断表达式 ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); if (this.beanFactory != null) { ajexp.setBeanFactory(this.beanFactory); } return ajexp; }
getAdvisor函数就是根据作为参数传入的切面实例的方法上的注解来生成Advisor实例,也就是
InstantiationModelAwarePointcutAdvisorImpl对象。依据方法上的切入点表达式生成
AspectJExpressionPointcut。
我们都知道
PointcutAdvisor实例中必然有一个
Pointcut和
Advice实例。修饰在方法上的注解包括:
@Pointcut,
@Around,
@Before,
@After,
@AfterReturning和
@AfterThrowing,所以
InstantiationModelAwarePointcutAdvisorImpl会依据不同的不同的注解生成不同的
Advice通知。
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { // .... 省略成员变量的直接赋值 // 单例模式时 this.pointcut = this.declaredPointcut; this.lazy = false; // 按照注解解析 Advice this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); }
InstantiationModelAwarePointcutAdvisorImpl的构造函数中会生成对应的
Pointcut和
Advice。
instantiateAdvice函数调用了
ReflectiveAspectJAdvisorFactory的
getAdvice函数。
// ReflectiveAspectJAdvisorFactory public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); // 获取 Advice 注解 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // 检查是否为AspectJ注解 if (!isAspect(candidateAspectClass)) { throw new AopConfigException("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]"); } AbstractAspectJAdvice springAdvice; // 按照注解类型生成相应的 Advice 实现类 switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; case AtAround: // @Before 生成 AspectJMethodBeforeAdvice springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: // @After 生成 AspectJAfterAdvice springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: // @AfterReturning 生成 AspectJAfterAdvice springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: // @AfterThrowing 生成 AspectJAfterThrowingAdvice springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: // @Around 生成 AspectJAroundAdvice 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); } // 配置Advice springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); // 获取方法的参数列表方法 String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { // 设置参数名称 springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }
至此,Spring AOP就获取了容器中所有的
Advisor实例,下一步在每个实例初始化完成后,根据这些
Advisor的
Pointcut切入点进行筛选,获取合适的
Advisor实例,并生成代理实例。
后记
Spring AOP后续文章很快就会更新,请大家继续关注。
相关文章推荐
- Spring AOP 学习之Advisor
- Spring与AOP_名称匹配方法切入点顾问(Advisor)
- Spring中切面的<aop:advisor pointcut="execution参数解析
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP
- Spring Aop(八)——advisor标签
- Spring3系列10- Spring AOP——Pointcut,Advisor拦截指定方法
- 死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator
- Spring中基于AOP的XML架构
- Spring AOP 架构
- Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator
- 深入解析Spring架构与设计原理(二)AOP原理
- Spring 源码分析(三) —— AOP(二)Spring AOP 整体架构
- spring错误处理 Build path is incomplete. Cannot find class file for org.springframework.aop.Advisor
- 深入解析Spring架构与设计原理-AOP
- Spring AOP 之 RegexpMethodPointcutAdvisor
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP
- Spring3- Spring AOP——Pointcut,Advisor
- spring Aop中aop:advisor 与 aop:aspect的区别
- Spring Aop之Advisor解析
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP