前言

本篇文章是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)@Documentedpublic @interface MyMethod {}

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

public interface IMyService {    void executeTask(String message);    void tempExecute(String message);}@Servicepublic 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@Componentpublic 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@EnableAspectJAutoProxypublic 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将理论的动静代理对象生成进去。