foreword

This article is the source code learning and sharing of SpringAOP . It is divided into two parts. This article is a source code study of the part of generating dynamic proxy objects for business beans when the aspects are weaved into business beans in SpringAOP .

text

1. Example project construction

The related dependencies of Spring are introduced by introducing Springboot . The dependencies are as follows.

 <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>

The Springboot version used is 2.4.1 , and the corresponding Spring version is 5.3.2 .

First customize an annotation to locate the target method in the pointcut, as shown below.

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

Then define the business interface and implementation class as shown below.

 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);
    }

}

Then define a facet, known 切面 = 切点 + 通知 , in this example project, the pointcut is all methods modified by @MyMethod annotation, and select the pre-notification and post-notification, as follows Show.

 @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.");
    }

}

Customize a configuration class and place it in the same package path as all the above classes, as shown below.

 @ComponentScan
@EnableAspectJAutoProxy
public class MyConfig {}

Finally write a test program as shown below.

 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.");
    }

}

Run the test program and print the following.

It can be seen that when the executeTask() method is run, the aspect logic takes effect.

2. Timing diagram

The generation of dynamic proxy objects in SpringAOP can be divided into two major steps.

  • Step 1 : Get the notification acting on the current bean and get the notification chain ;
  • Step 2 : Generate an AOP dynamic proxy object for the current bean based on the notification chain, and decide whether to use the CGLIB dynamic proxy or the JDK dynamic proxy according to the configuration and target bean .

The notification chain can be represented as follows.

 List<Advisor> chain

Advisor Interface is a top-level abstraction for advice in SpringAOP . It has two sub-interfaces. The class diagram is shown below.

PointcutAdvisor is an abstraction of pointcut-related notifications, and PointcutAdvisor can be understood as the encapsulation of notification methods and pointcuts , because the notifications in the aspects of the example project in this article are all Pointcut related notifications, so unless otherwise specified, Advisor all refer to PointcutAdvisor , and ---7e2c7c96d6c080029bc2bebef8b4fd00 Advisor can also be called a notification less rigorously.

After clarifying the concept, the sequence diagram is given below. There are two sequence diagrams, one is the acquisition sequence diagram of the notification chain, and the other is the generation sequence diagram of the AOP dynamic proxy object, as shown below.

  • The acquisition sequence diagram of the notification chain.

  • Generation sequence diagram of AOP dynamic proxy object.

The subsequent source code analysis can be understood in conjunction with the above sequence diagram.

Three. SpringAOP dynamic proxy object generation time point

In the sample project, if you observe the iMyService field through the method of breakpoint debugging, you can find that it is a dynamic proxy object, as shown below.

In the bean life cycle, bean instantiation, attribute injection and initialization are all in the AbstractAutowireCapableBeanFactory doCreateBean() method of ---8c7988ff9f92c295cae86007f942fdc9---, in which the createBeanInstance() method will be called first. Instantiate the bean , then call the populateBean() method to complete the property injection for the bean instance, and finally call the initializeBean() method to initialize the bean . Let's take a look at the implementation of the initializeBean() method.

 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;
}

When the bean is initialized, the BeanPostProcessors ( bean post-processor) postProcessBeforeInitialization() and postProcessAfterInitialization() methods are called, in BeanPostProcessors In the postProcessAfterInitialization() method of the implementation class AnnotationAwareAspectJAutoProxyCreator , the bean will be woven into the aspect (a dynamic proxy object will be generated for the bean ).

The class diagram of AnnotationAwareAspectJAutoProxyCreator is given below.

4. Obtaining the notification chain

As known in the previous section, in the BeanPostProcessors --- method of the implementation class AnnotationAwareAspectJAutoProxyCreator of the postProcessAfterInitialization() , the facet is woven for the bean (a dynamic proxy object is generated for the bean ), then use the AnnotationAwareAspectJAutoProxyCreator postProcessAfterInitialization() method of ---12dc725d3907d84c5f1e74a9b0fa27e8--- as the entry to start analyzing the source code.其实AnnotationAwareAspectJAutoProxyCreator postProcessAfterInitialization() ,那么实际调用到的是AnnotationAwareAspectJAutoProxyCreator父类AbstractAutoProxyCreatorpostProcessAfterInitialization() method, as shown below.

 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;
}

Continue to look at the implementation of the wrapIfNecessary() method, as shown below.

 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() method will first get the notification chain acting on the current bean , and then call the createProxy() method to create a dynamic proxy object for the current bean , so this section focuses on analysis getAdvicesAndAdvisorsForBean() Implementation of the method. getAdvicesAndAdvisorsForBean() is implemented as follows.

 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();
}

Continue to look at findEligibleAdvisors() method, as shown below.

 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()方法中会BeanFactoryAspectJAdvisorsBuilder The buildAspectJAdvisors() method to traverse each aspect in the current container modified by the @Aspect annotation, and then encapsulate the notification of each aspect into Advisor and return, at the same time Every time a slice is traversed, all the slices Advisor will be cached so that they can be directly obtained from the cache next time.

findEligibleAdvisors() In the method, after obtaining all the Advisor in the current container, it will call the findAdvisorsThatCanApply() method to find out the ---51eead52c2ec9 that can act on the current Advisor 51eead52c2ec9 Advisor , the judgment is based on Advisor in Pointcut .

findEligibleAdvisors() method will finally sort all the Advisor acting on the current bean , which will be analyzed later. Therefore, after the findEligibleAdvisors() method is executed, the corresponding Advisor of all notifications that can act on the current bean are obtained, and the notification chain is obtained.

Finally, let's analyze how the AnnotationAwareAspectJAutoProxyCreator findCandidateAdvisors() method of ---320baf1b6dc5ccc7087237a201171d45--- gets all the notifications in the container and how to encapsulate each notification into Advisor . The BeanFactoryAspectJAdvisorsBuilder buildAspectJAdvisors() is shown below.

 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;
}

The above buildAspectJAdvisors() method is mainly a caching strategy for Spring 's notification of aspect beans . The main idea is that the notification of all aspect beans will be obtained and generated for the first time. Advisor , and then cache it, and get it from the cache when you get the notification later. Let's continue to analyze in depth how the notification of the aspect bean is encapsulated into Advisor . The actual logic occurs in the ReflectiveAspectJAdvisorFactory getAdvisors() method, as shown below.

 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;
}

At this point, the source code analysis of the notification chain is completed. The following subsections are used to obtain the advice chain steps that act on a bean .

  • If it is the first time to get the notification chain, it will traverse each aspect bean in the container that is annotated by @Aspect and then encapsulate its notification into Advisor and cache it, if not the first Get all Advisor directly from the cache;
  • Then filter to get Advisor acting on the current bean , and add it to the collection;
  • Returns the filtered collection as the notification chain for the subsequent creation of AOP dynamic proxy objects.

5. Creation of AOP dynamic proxy objects

It is known that the AbstractAutoProxyCreator wrapIfNecessary() method of ---8fa6307d045ce095aef7be8bfa608ba2--- will first call the getAdvicesAndAdvisorsForBean() method to obtain the notification chain acting on the current bean , then the next step should be based on the notification chain for the current bean The bean generates the AOP dynamic proxy object, and the logic for generating the dynamic proxy object is in the AbstractAutoProxyCreator createProxy() method of ---dcc1caa116584072701b928f86f46f11---, as shown below.

 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());
}

In the createProxy() method, a ProxyFactory factory will be created first, and then the notification chain and target object will be set for the ---0d8c22fd5ef61083851834a1ce569818 ProxyFactory factory, and the subsequent dynamic proxy object is created ProxyFactory ProxyFactory Factory to complete. ProxyFactory factory class diagram is shown below.

So ProxyFactory is actually a AdvisedSupport . The ProxyFactory getProxy() is shown below.

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

ProxyFactorygetProxy()方法中会先调用到其父类ProxyCreatorSupport中的createAopProxy()方法, createAopProxy() The method will have two return values, one is JdkDynamicAopProxy , which is responsible for the generation of JDK dynamic proxy objects, and the other is CglibAopProxy ProxyCreatorSupport which is responsible for the generation of CGLIB dynamic proxy objects. ProxyCreatorSupport the implementation of the createAopProxy() method.

 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()方法中创建---3ca3e3a79bdf727418638482a92631ba AopProxy时会将---9f66b23857e2a0f81c28fdeff25d5d6b ProxyFactory ,所以创建出来的AopProxy也Just pass ProxyFactory to hold the notification chain and the target object. ProxyFactorygetProxy()方法, JdkDynamicAopProxy CglibAopProxy ,就会调用其getProxy() to generate a dynamic proxy object, the following is an example of the JdkDynamicAopProxy getProxy() method of JdkDynamicAopProxy , getProxy() method ---ad04de88a41 --- shown below .

 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);
}

The JdkDynamicAopProxy getProxy() method of ---18509e26d9e5d3bbf889aeaf18c3b587--- is to call the Proxy method of newProxyInstance() to create a JDK dynamic proxy---method.

So far, the source code analysis of creating AOP dynamic proxy objects in Spring AOP is completed. The steps to create a dynamic proxy object for a bean based on the advice chain are given below.

  • Create ProxyFactory , set the notification chain and target object for ProxyFactory d4fabdfd1287e89aa46aafd56a843fff---, and then create a dynamic proxy object through ProxyFactory ;
  • Through ProxyFactory first create AopProxy , depending on the dynamic proxy method used, the created ObjenesisCglibAopProxy AopProxy can be JdkDynamicAopProxy ObjenesisCglibAopProxy , and ProxyFactory passed in itself when creating AopProxy , so the chain created AopProxy holds the notification and target objects;
  • The dynamic proxy object is generated by the created AopProxy .

Summarize

There are user-defined aspects in Spring and aspects provided by the Spring framework. These aspects will be woven into the bean when the postProcessAfterInitialization() BeanPostProcessors in the life cycle of the bean . It is to generate AOP dynamic proxy objects for beans . Before generating a dynamic proxy object for a bean , it will first obtain all the notifications in the container that can act on the bean . These notifications will be encapsulated into the implementation class of Advisor and added to the collection, which can be called this Advisor The collection of Advisor AopProxy the notification chain. After obtaining the notification chain, a ProxyFactory ProxyFactory factory will be created to help create a dynamic proxy object. AopProxy ,根据使用的动态代理方式的不同,创建出来的AopProxy d8f8904fbb4817f66fe9bc82a324ce0e---可以为---68b5ab7cdee92a94fa96cbf09eb8fd2a JdkDynamicAopProxy ObjenesisCglibAopProxyProxyFactory When creating AopProxy , it passed in itself, so the created AopProxy also held the notification chain and the target object, and finally passed AopProxy to the actual A dynamic proxy object is generated.


半夏之沫
65 声望31 粉丝