您现在的位置是:首页 >技术杂谈 >Spring AOP之EnableAspectJAutoProxy原理网站首页技术杂谈

Spring AOP之EnableAspectJAutoProxy原理

程序员侠客行 2025-05-02 00:01:02
简介Spring AOP之EnableAspectJAutoProxy原理

《Spring AOP实现浅析三之执行代理》中,我们已熟悉了代理执行过程。本文中,我们将探究@EnableAspectJAutoProxy的底层实现:

  • Spring中如何将@Aspect、 @Before等处理为Advisor?
  • 在bean生命周期的哪个阶段创建了代理对象?

一 EnableAspectJAutoProxy注解

1.1 认识注解

要启用Spring AOP功能,得在配置类上添加@EnableAspectJAutoProxy。

这个注解有两个属性:

  • proxyTargetClass:是否要创建基于子类的CGLIB代理,而不是基于Java接口的代理。默认值为false,即使用JDK代理实现。
  • exposeProxy:将代理对象由AOP框架作为ThreadLocal公开,以便通过AopContext类获取。默认关闭。

可见,Spring AOP默认使用JDK动态代理,默认不将代理对象暴露给线程。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}

1.2 导入AspectJAutoProxyRegistrar类

EnableAspectJAutoProxy注解通过@Import导入了AspectJAutoProxyRegistrar类。

该类实现了ImportBeanDefinitionRegistrar接口,复写了registerBeanDefinitions()方法,主要逻辑是:

  1. 向Spring容器添加AnnotationAwareAspectJAutoProxyCreator的beanDefinition;
  2. 获取注解的属性值,并设置到beanDefinition中。

新添加的beanName就是"org.springframework.aop.config.internalAutoProxyCreator"。

解析advisor、生成代理对象的逻辑都在AnnotationAwareAspectJAutoProxyCreator类中。

二 AbstractAutoProxyCreator类

AnnotationAwareAspectJAutoProxyCreator类是AbstractAutoProxyCreator的子类。

AbstractAutoProxyCreator 是Spring AOP的核心类之一,它实现了SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware 接口,在postProcessAfterInitialization()方法中,实现了代理对象的创建。

wrapIfNecessary方法逻辑为:

  1. 跳过不需要代理的bean,如targetSource类型的bean、未命中切面的bean;

  2. 获取当前bean能匹配的Advisor,有则创建并返回代理对象,无则返回当前对象。

  3. 期间会维护缓存Map<Object, Boolean> advisedBeans。

如何创建代理对象,在《Spring AOP实现浅析 一》《Spring AOP实现浅析 二》《Spring AOP实现浅析 三》博文中,已做了详细介绍。

现在,我们详细看看一个bean如何匹配Advisor?

三 匹配Advisor

在子类AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean方法中,做了这些事:

  1. 找出Spring容器中所有的Advisor对象;
  2. 与当前bean匹配,得到适用的eligibleAdvisors;
  3. 向eligibleAdvisors中添加扩展的Advisor;
  4. 对eligibleAdvisors排序后返回。

3.1 找出所有Advisor对象

3.1.1 从容器中找Advisor对象

父类AbstractAdvisorAutoProxyCreator的findCandidateAdvisors方法,只会从容器中找所有Advisor类型的bean。

主要代码如下:

public List<Advisor> findAdvisorBeans() {
    // 找所有Advisor类型的beanName
    String[] advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
        this.beanFactory, Advisor.class, true, false);
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    // 遍历names,获取bean
    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            try {
                advisors.add(this.beanFactory.getBean(name, Advisor.class));
            }
            catch (BeanCreationException ex) {
            }
        }     
    }
    return advisors;
}

而子类AnnotationAwareAspectJAutoProxyCreator复写后,还会额外从@Aspect标注的类构建advisor。

3.1.2将@Aspect的类解析为Advisor

大体流程为:

  1. 当一个bean的类上有@Aspect注解时,就需要被处理;这样的bean将被缓存到aspectBeanNames中(一个List)。

  1. 将bean封装为BeanFactoryAspectInstanceFactory;从中解析advisor;

  1. 从类中解析到的Advisor会被缓存(避免重复解析)。

advisorFactory是一个ReflectiveAspectJAdvisorFactory类对象,完成了从method到advisor的转化。

  • 找出类中没有@Pointcut的所有方法,包括hashCode、equals等;然后排序(按照@Around、@Before等注解顺序);

  • 如果方法上没有Pointcut、Around、Before等注解,则跳过;
  • 将注解中expression表达式封装为Pointcut对象;将方法封装为Advice对象;如:
    • 将@Around的方法,封装为AspectJAroundAdvice对象;
    • 将@Before的方法,封装为AspectJMethodBeforeAdvice对象;

  • 一个Pointcut和一个Advice就组成了Advisor对象。

3.2 给bean匹配Advisor

将找到的所有advisor对象,依次与当前bean匹配,无非就是根据Pointcut的ClassFilter、MethodMatcher来判断。简化逻辑如下:

List<Advisor> matched = new ArrayList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
    // ClassFilter
    if(candidate.getClassFilter().matches(targetClass)){
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(targetClass);
        // 方法匹配
        for (Method method : methods) {
            if (candidate.getMethodMatcher().matches(method, targetClass)){
                matched.add(candidate);
                break;
            }
        }
    }
}

当bean中任意方法匹配了任意advisor,那么就需要为这个bean创建代理对象。

四 创建代理对象

调用AbstractAutoProxyCreator#createProxy方法,传入bean对象、beanName和匹配的Advisor集合,构建ProxyFactory对象来创建代理类。

Object proxy = createProxy(bean.getClass(), beanName,
 specificInterceptors, new SingletonTargetSource(bean));

五 总结

  1. AbstractAdvisorAutoProxyCreator只会从容器中找所有Advisor类型的bean,而AnnotationAwareAspectJAutoProxyCreator类,还会从@Aspect标注的Bean中构建Advisor对象。
  2. @EnableAspectJAutoProxy,就是向Spring容器中添加了一个BeanPostProcessor接口实现(AnnotationAwareAspectJAutoProxyCreator),从而开启了AOP,在实例化后阶段为被切面命中的bean创建代理对象。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。