Spring系列之Spring框架和SpringAOP集成过程分析(十)

在开始这个系列之前大家先想一下我们是怎么在项目中使用SpringAOP的(这里的分析都是基于AspectJ注解的)。我们需要在我们的Spring配置文件中引入SpringAOP的命名空间和标签,然后定义切面Bean,进行AOP配置。大概如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       <!--AOP的命名空间-->
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启自动包扫描-->
    <context:component-scan base-package="com.zkn.spring.learn.aop.spring"/>
    <!--使用AspectJ注解-->
    <aop:aspectj-autoproxy/>
</beans>

我们在使用Spring中不同的功能的时候可能会引入不同的命名空间比如xmlns:context,xmlns:aop,xmlns:tx等等。关于命名空间的东西我们这里先不多说。在Spring中定义了一个这样的抽象类专门用来解析不同的命名空间。这个类是NamespaceHandler,我们看一下这个和这个类相关的一些子类:
Spring系列之Spring框架和SpringAOP集成过程分析(十)
在不同的命名空间实现类中定义了不同类型的实现类,这些实现类主要是用来初始化一些解析对应的标签的类。比如我们接下来要分析的AopNamespaceHandler这个类。在上面关于AOP的配置中,我们使用了一个AOP的标签:

<aop:aspectj-autoproxy/>

为什么我们只要使用这个标签,就可以使用SpringAOP的功能呢?看一下AopNamespaceHandler这个类的内容你就会明白了:

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        //我们看到了这样的一段代码  aspectj-autoproxy这个再加上aop 是不是就是 aop:aspectj-autoproxy呢
        //这段代码的意思是使用AspectJAutoProxyBeanDefinitionParser来解析aop:aspectj-autoproxy标签
        //AspectJAutoProxyBeanDefinitionParser这个类就是SpringAOP和Spring框架结合的关键
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

}

PS:每个框架对应的NamespaceHandler就是你分析Spring中的对应框架的关键入口。
下面我们来分析一下AspectJAutoProxyBeanDefinitionParser这个类。先看一下它的parse方法。

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //这个地方是向ApplicationContext中注入使用AspectJ注解自动创建代理对象的bean
        AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        extendBeanDefinition(element, parserContext);
        return null;
    }

AopNamespaceUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary的方法内容如下:

    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {
        //parserContext.getRegistry()这个是获取到的全局的BeanDefinitionRegistry
        //我们看这个方法做了什么
        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        //这两个方法的内容一看就知道是什么意思了 就先不分析了
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }

AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary

    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source)     {
        //这里传入了一个AnnotationAwareAspectJAutoProxyCreator的class
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }
    
    private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        //这里先判断是不是已经注入过name为org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition了
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            //如果已经注入过了 判断之前注入的BeanDefinition的Class和传入的Class是不是一致
            BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                //如果不一致的话 则取他们的优先级
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                //优先级高的生效 这个优先级 一会儿说
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }
            return null;
        }
        //如果之前没有向BeanDefinitionRegistry中注入过此beanname的BeanDefinition
        //那就创建一个新的BeanDefinition添加到BeanDefinitionRegistry中
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }

我们上面提到了一个优先级的东西,那这个优先级是在哪儿定义的呢?在AopConfigUtils中有这样的一段代码:

    static {
        APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    }

在AopConfigUtils初始化的时候就会向APC_PRIORITY_LIST中添加这三个Class类。而上面提到的优先级就是他们在APC_PRIORITY_LIST中的位置。由此可见AspectJAwareAdvisorAutoProxyCreator会覆盖InfrastructureAdvisorAutoProxyCreatorBeanDefinition中的class,而AnnotationAwareAspectJAutoProxyCreator又会覆盖AspectJAwareAdvisorAutoProxyCreator的BeanDefinition中的class(当然也会覆盖InfrastructureAdvisorAutoProxyCreator的BeanDefinition)。而我们在上面传入的Class是AnnotationAwareAspectJAutoProxyCreator,即是优先级最大的Class。说了半天,这三个Class都有什么用呢?和我们今天说的SpringAOP又有什么关系呢?通过上面的分析,我们只知道使用

<aop:aspectj-autoproxy/>

会向BeanDefinitionRegistry中注入一个beanClass为AnnotationAwareAspectJAutoProxyCreator的Bean。
我们先来看一下这三个类的关系:
Spring系列之Spring框架和SpringAOP集成过程分析(十)
我们发现他们三个是同一个类的子类:AbstractAdvisorAutoProxyCreator,这个类的作用是创建代理对象并为每个代理对象找到合适的Advisor(这一部分的东西可以参考前面的博文),那么它的子类也具有相同的功能。AnnotationAwareAspectJAutoProxyCreator主要是为AspectJ注解服务的,InfrastructureAdvisorAutoProxyCreator是一个基础建设性的类,即识别不使用AspectJ注解的AOP配置(比如事务的实现)。OK,我们在上废话了一大堆其实就是说了一件事:那就是在Spring启动的时候会使用AopNamespaceHandler和AspectJAutoProxyBeanDefinitionParser来解析AOP标签,并注入对应的BeanDefinition(AnnotationAwareAspectJAutoProxyCreator和InfrastructureAdvisorAutoProxyCreator)。
我们在项目中使用AspectJ注解比较多,所以我们在下篇文章中会分析一下AnnotationAwareAspectJAutoProxyCreator这个类。

上一篇:Java开源项目,2021年GitHub top10。


下一篇:Spring系列之AOP分析之对目标对象的拦截过程(七)