关于spring:SpringSpringAOP源码学习上

10次阅读

共计 14120 个字符,预计需要花费 36 分钟才能阅读完成。

前言

本篇文章是 SpringAOP 的源码学习分享,分为高低两篇,本篇是对 SpringAOP 中切面织入业务 bean 时为业务 bean 生成动静代理对象的这一块的源码学习。

注释

一. 示例工程搭建

通过引入 Springboot 来实现引入 Spring 的相干依赖,依赖项如下所示。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencies>

应用的 Springboot 版本为 2.4.1,对应的Spring 版本为5.3.2

首先自定义一个注解,用于在切点中定位到指标办法,如下所示。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyMethod {}

而后定义业务接口和实现类,如下所示。

public interface IMyService {void executeTask(String message);

    void tempExecute(String message);

}

@Service
public class MyService implements IMyService {

    @Override
    @MyMethod
    public void executeTask(String message) {System.out.println(message);
    }

    @Override
    public void tempExecute(String message) {executeTask(message);
    }

}

而后定义一个切面,已知 切面 = 切点 + 告诉 ,在本示例工程中,切点是所有由@MyMethod 注解润饰的办法,并且抉择前置告诉和后置告诉,如下所示。

@Aspect
@Component
public class MyAspect {@Pointcut("@annotation(com.learn.aop.aspect.MyMethod)")
    public void myMethodPointcut() {}

    @Before(value = "myMethodPointcut()")
    public void commonBeforeMethod(JoinPoint joinPoint) {System.out.println("Common before method.");
    }

    @After(value = "myMethodPointcut()")
    public void commonAfterMethod(JoinPoint joinPoint) {System.out.println("Common after method.");
    }

}

自定义一个配置类,和下面所有类放在同一包门路下,如下所示。

@ComponentScan
@EnableAspectJAutoProxy
public class MyConfig {}

最初编写一个测试程序,如下所示。

public class MyTest {public static void main(String[] args) {
        ApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(MyConfig.class);

        IMyService iMyService = applicationContext.getBean(IMyService.class);

        iMyService.tempExecute("Real method execute.");
        iMyService.executeTask("Real method execute.");
    }

}

运行测试程序,打印如下。

能够看到运行 executeTask() 办法时,切面逻辑失效了。

二. 时序图

SpringAOP中动静代理对象的生成,能够分为两个大的步骤。

  • 步骤一 :将作用于以后bean 的告诉获取进去,失去 告诉链
  • 步骤二 :基于告诉链为以后bean 生成 AOP 动静代理对象,并依据配置和指标 bean 决定是应用 CGLIB 动静代理还是 JDK 动静代理。

告诉链能够示意如下。

List<Advisor> chain

Advisor接口是 SpringAOP 中对告诉的一个顶层形象,其有两个子接口,类图如下所示。

PointcutAdvisor是对切点相干的告诉的形象,能够将 PointcutAdvisor 了解为对 告诉办法 切点 的封装,因为本文的示例工程中的切面中的告诉全副是切点相干的告诉,所以无非凡阐明时,Advisor均指 PointcutAdvisor,并且也能够不太谨严的将Advisor 称为告诉。

在理清了概念之后,上面给出时序图,时序图有两张,一张是告诉链的获取时序图,一张是 AOP 动静代理对象的生成时序图,如下所示。

  • 告诉链的获取时序图。

  • AOP动静代理对象的生成时序图。

后续源码的剖析能够联合上述时序图进行了解。

三. SpringAOP 动静代理对象生成工夫点

在示例工程中,如果通过断点调试的办法,察看 iMyService 字段,能够发现其是一个动静代理对象,如下所示。

bean 生命周期中,bean的实例化,属性注入和初始化都在 AbstractAutowireCapableBeanFactorydoCreateBean()办法中,在该办法中会先调用 createBeanInstance() 办法将 bean 实例化进去,而后调用 populateBean() 办法为 bean 实例实现属性注入,最初调用 initializeBean() 办法来初始化 bean。上面看一下initializeBean() 办法的实现。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    
    ......
    
    if (mbd == null || !mbd.isSynthetic()) {// 调用 BeanPostProcessors 的 postProcessBeforeInitialization()办法
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    ......
    
    if (mbd == null || !mbd.isSynthetic()) {// 调用 BeanPostProcessors 的 postProcessAfterInitialization()办法
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

在初始化 bean 的时候,就会调用到 BeanPostProcessorsbean 后置处理器)的 postProcessBeforeInitialization()postProcessAfterInitialization()办法,在 BeanPostProcessors 的实现类 AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization()办法中,就会为 bean 织入切面(为 bean 生成动静代理对象)。

上面给出 AnnotationAwareAspectJAutoProxyCreator 的类图。

四. 告诉链的获取

上一节中已知,在 BeanPostProcessors 的实现类 AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization()办法中,就会为 bean 织入切面(为 bean 生成动静代理对象),那么就以 AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization()办法为入口,开始剖析源码。其实 AnnotationAwareAspectJAutoProxyCreator 没有对 postProcessAfterInitialization() 办法做实现,那么理论调用到的是 AnnotationAwareAspectJAutoProxyCreator 父类 AbstractAutoProxyCreatorpostProcessAfterInitialization()办法,如下所示。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 如果 bean 是切面作用指标,就为 bean 生成动静代理对象
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

持续看 wrapIfNecessary() 办法的实现,如下所示。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // 把作用在以后 bean 的告诉获取进去
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 为以后 bean 生成动静代理对象
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        // 返回以后 bean 的动静代理对象
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

wrapIfNecessary()办法会先将作用于以后 bean 的告诉链获取进去,而后再调用 createProxy() 办法为以后 bean 创立动静代理对象,那么本大节重点剖析 getAdvicesAndAdvisorsForBean() 办法的实现。getAdvicesAndAdvisorsForBean()实现如下。

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    // 将作用于以后 bean 的告诉获取进去,并且告诉会被封装成 Advisor 的实现类
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {return DO_NOT_PROXY;}
    return advisors.toArray();}

持续看 findEligibleAdvisors() 办法,如下所示。

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 找到容器中所有由 @Aspect 注解润饰的切面,并将切面中的每个告诉办法都封装成一个 Advisor 的实现类
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 在 candidateAdvisors 中将作用于以后 bean 的 Advisor 获取进去
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // 对 Advisor 进行排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

findEligibleAdvisors()办法中会先调用到 AnnotationAwareAspectJAutoProxyCreatorfindCandidateAdvisors()办法,在 findCandidateAdvisors() 办法中会再调用 BeanFactoryAspectJAdvisorsBuilderbuildAspectJAdvisors()办法来遍历以后容器中的每个由 @Aspect 注解润饰的切面,而后将每个切面的告诉封装成 Advisor 并返回,同时每遍历一个切面,都会将这个切面的所有 Advisor 缓存,以便下次获取时间接从缓存获取。

findEligibleAdvisors()办法中在获取到以后容器中的所有 Advisor 后,会再调用 findAdvisorsThatCanApply() 办法来找出可能作用于以后 beanAdvisor,判断根据就是依据 Advisor 中的 Pointcut 来判断。

findEligibleAdvisors()办法最初还会对作用于以后 bean 的所有 Advisor 进行排序,这个前面再剖析。所以 findEligibleAdvisors() 办法执行完,就获取到了可能作用于以后 bean 的所有告诉对应的Advisor,也就获取到了告诉链。

最初再剖析一下 AnnotationAwareAspectJAutoProxyCreatorfindCandidateAdvisors()办法中是如何获取容器中所有告诉以及是如何将每个告诉封装成 Advisor 的。BeanFactoryAspectJAdvisorsBuilderbuildAspectJAdvisors() 办法如下所示。

public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;
    //aspectNames 不为 null 示意获取过切面 bean 的告诉并把这些告诉进行了缓存,那么间接从缓存获取告诉
    if (aspectNames == null) {synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                // 把容器中的 bean 的名字获取进去
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
                // 遍历每个 bean
                for (String beanName : beanNames) {if (!isEligibleBean(beanName)) {continue;}
                    Class<?> beanType = this.beanFactory.getType(beanName, false);
                    if (beanType == null) {continue;}
                    // 判断 bean 是否是切面 bean
                    if (this.advisorFactory.isAspect(beanType)) {
                        // 把切面 bean 的名字增加到汇合中,以便后续缓存起来
                        aspectNames.add(beanName);
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // 调用到 ReflectiveAspectJAdvisorFactory 的 getAdvisors()办法来获取切面 bean 里的告诉
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            if (this.beanFactory.isSingleton(beanName)) {
                                // 如果切面 bean 是单例,则缓存切面 bean 的告诉
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                // 如果切面 bean 不是单例,则缓存切面 bean 的工厂
                                // 通过切面 bean 的工厂能够每次都生成切面 bean 的告诉
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                        else {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;
            }
        }
    }

    // 执行到这里示意曾经生成过告诉并进行了缓存
    if (aspectNames.isEmpty()) {return Collections.emptyList();
    }
    List<Advisor> advisors = new ArrayList<>();
    for (String aspectName : aspectNames) {
        // 将每个切面 bean 的告诉从缓存中获取进去并加到后果汇合中
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);
        }
        else {
            // 非单例切面 bean 就应用其对应的工厂新生成告诉,而后也退出到后果汇合中
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    // 返回容器中的所有告诉
    return advisors;
}

下面 buildAspectJAdvisors() 办法中次要是 Spring 对切面 bean 的告诉的一个缓存策略,次要思维就是第一次获取时会实在的将所有切面 bean 的告诉获取进去并生成 Advisor,而后缓存起来,后续再获取告诉时就从缓存中获取。上面持续深入分析一下切面bean 的告诉是如何被封装成 Advisor 的,理论的逻辑产生在 ReflectiveAspectJAdvisorFactorygetAdvisors()办法中,如下所示。

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 失去切面 bean 的 Class 对象
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 失去切面 bean 的名字
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);

    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();
    // 调用 getAdvisorMethods()办法来把非切点办法获取进去,并遍历
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 先将告诉上的切点结构成 AspectJExpressionPointcut,而后再创立告诉对应的 Advisor
        // 创立进去的 Advisor 理论为 InstantiationModelAwarePointcutAdvisorImpl
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
        // 以后 method 如果是告诉办法,则将告诉办法对应的 Advisor 增加到后果汇合中
        // 如果不是告诉办法,失去的 Advisor 会为 null,就不会增加到后果汇合中
        if (advisor != null) {advisors.add(advisor);
        }
    }

    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {advisors.add(advisor);
        }
    }

    return advisors;
}

至此获取告诉链的源码剖析结束。上面对获取作用于某个 bean 的告诉链步骤进行大节。

  • 如果是第一次获取告诉链,那么会遍历容器中每个由 @Aspect 注解润饰的切面 bean 而后将其告诉封装成 Advisor 并缓存起来,如果不是第一次获取,就间接从缓存中将所有 Advisor 获取进去;
  • 而后筛选失去作用于以后 beanAdvisor,并退出汇合中;
  • 返回筛选失去的汇合,作为后续创立 AOP 动静代理对象的告诉链。

五. AOP 动静代理对象的创立

已知在 AbstractAutoProxyCreatorwrapIfNecessary()办法中会先调用 getAdvicesAndAdvisorsForBean() 办法获取作用于以后 bean 的告诉链,那么下一步就应该基于告诉链为以后 bean 生成 AOP 动静代理对象,生成动静代理对象的逻辑在 AbstractAutoProxyCreatorcreateProxy()办法中,如下所示。

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    // 创立 ProxyFactory 来创立动静代理对象
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);
        }
        else {evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 为 ProxyFactory 设置告诉链
    proxyFactory.addAdvisors(advisors);
    // 为 ProxyFactory 设置指标对象
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);
    }

    // 调用 ProxyFactory 的 getProxy()办法创立动静代理对象
    return proxyFactory.getProxy(getProxyClassLoader());
}

createProxy() 办法中会先创立一个 ProxyFactory 工厂,而后为 ProxyFactory 工厂设置告诉链和指标对象,后续的动静代理对象的创立就是由 ProxyFactory 工厂来实现。ProxyFactory工厂类图如下所示。

所以 ProxyFactory 其实是一个 AdvisedSupportProxyFactorygetProxy()办法如下所示。

public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);
}

ProxyFactorygetProxy()办法中会先调用到其父类 ProxyCreatorSupport 中的 createAopProxy() 办法,createAopProxy()办法会有两种返回值,一个是 JdkDynamicAopProxy,负责JDK 动静代理对象的生成,另一个是 CglibAopProxy,负责CGLIB 动静代理对象的生成,上面看一下 ProxyCreatorSupportcreateAopProxy()办法的实现。

protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();
    }
    //getAopProxyFactory()会返回一个 AopProxyFactory
    //AopProxyFactory 的 createAopProxy()会返回一个 AopProxy
    // 依据不同的指标类和不同的配置,会最终决定 AopProxy 是 JdkDynamicAopProxy 还是 CglibAopProxy
    // 创立 AopProxy 时还会将 ProxyFactory 本人传入,所以创立进去的 AopProxy 也就持有了告诉链和指标对象
    return getAopProxyFactory().createAopProxy(this);
}

ProxyCreatorSupportcreateAopProxy() 办法中创立 AopProxy 时会将 ProxyFactory 传入,所以创立进去的 AopProxy 也就通过 ProxyFactory 持有了告诉链和指标对象。当初回到 ProxyFactorygetProxy()办法,在拿到 JdkDynamicAopProxy 或者 CglibAopProxy 之后,就会调用其 getProxy() 办法来生成动静代理对象,上面以 JdkDynamicAopProxygetProxy()办法为例进行阐明,JdkDynamicAopProxygetProxy() 办法如下所示。

public Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isTraceEnabled()) {logger.trace("Creating JDK dynamic proxy:" + this.advised.getTargetSource());
    }
    // 调用 Proxy 的 newProxyInstance()办法来生成动静代理对象
    //proxiedInterfaces 中有 bean 实现的接口
    //JdkDynamicAopProxy 本身是实现了 InvocationHandler 接口,所以这将 JdkDynamicAopProxy 传到了 newProxyInstance()办法中
    return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}

JdkDynamicAopProxygetProxy() 办法就是调用 ProxynewProxyInstance()办法来创立 JDK 动静代理对象。

至此 SpringAOP 中创立 AOP 动静代理对象的源码剖析结束。上面给出为 bean 基于告诉链创立动静代理对象的步骤大节。

  • 创立 ProxyFactory,为ProxyFactory 设置告诉链和指标对象,后续通过 ProxyFactory 创立动静代理对象;
  • 通过 ProxyFactory 先创立 AopProxy,依据应用的动静代理形式的不同,创立进去的AopProxy 能够为 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy,并且ProxyFactory 在创立 AopProxy 时传入了本身,所以创立进去的 AopProxy 也就持有了告诉链和指标对象;
  • 通过创立进去的 AopProxy 生成动静代理对象。

总结

Spring中有用户自定义的切面以及 Spring 框架提供的切面,这些切面会在 bean 的生命周期调用到 BeanPostProcessorspostProcessAfterInitialization()办法时织入 bean,织入的模式就是为bean 生成 AOP 动静代理对象。为 bean 生成动静代理对象前会先获取到容器中所有可能作用于这个 bean 的告诉,这些告诉会被封装成 Advisor 的实现类并退出到汇合中,能够称这个 Advisor 的汇合为告诉链,获取到告诉链后,会创立一个 ProxyFactory 工厂来帮忙创立动静代理对象,创立前会先通过 ProxyFactory 创立 AopProxy,依据应用的动静代理形式的不同,创立进去的AopProxy 能够为 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy,并且ProxyFactory 在创立 AopProxy 时传入了本身,所以创立进去的 AopProxy 也就持有了告诉链和指标对象,最初就是通过 AopProxy 将理论的动静代理对象生成进去。

正文完
 0