【源码】Spring AOP 14 原理解读三

前言

一般的,我们使用 Spring AOP 时,会在对应的配置类加上 @EnableAspectJAutoProxy 注解以开启 AOP 能力,本章节就以此入手,总结一下 Spring AOP 的整体原理

EnableAspectJAutoProxy

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

	// 是否代理目标对象,即是否 CGLIB 代理
	boolean proxyTargetClass() default false;

	// 是否暴露代理对象到 AopContext
	boolean exposeProxy() default false;

}
  • 基于注解暴露了 proxyTargetClassexposeProxy 属性
  • 核心是 Import 了一个 AspectJAutoProxyRegistrar
可以看到 Spring 是默认 JDK 代理的(proxyTargetClass = false)
但是 Spring Boot 是默认 CGLIB 哦,可参考 AopAutoConfiguration

AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		// 注册核心组件 AnnotationAwareAspectJAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 基于注解上的属性做标识,创建代理的时候用 ...
	}

}
  • 它是一个 ImportBeanDefinitionRegistrar,因此会在 registerBeanDefinitions 方法中注册对应的 BeanDefinition
  • 此处基于 AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary 方法注册我们上一章节了解的 AnnotationAwareAspectJAutoProxyCreator

AopConfigUtils

public abstract class AopConfigUtils {
	
	// 内置 beanName
	public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";

	private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

	/**
	 * 这里借由 List 来维护这几个 AbstractAutoProxyCreator 的等级
	 * 从上到下依次提高,功能越来越强嘛
	 */
	static {
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}

	// ...

	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
		return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
	}

	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		/**
		 * AnnotationAwareAspectJAutoProxyCreator
		 * 这里注册的是 AnnotationAwareAspectJAutoProxyCreator
		 * 		它是最高等级,所以只会覆盖其他(如果有的话)
		 * 举个例子,如果 Spring AOP 和 Spring Cache 都存在
		 * 		那就是 AnnotationAwareAspectJAutoProxyCreator
		 * 		覆盖 InfrastructureAdvisorAutoProxyCreator 咯
		 */
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

	/** registerOrEscalateApcAsRequired **/

	@Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		/**
		 * 先从容器中查看是否有目标 bean
		 * 如果容器中的 internalAutoProxyCreator 等级比当前低,那就覆盖
		 */
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			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;
		}

		// 如果不存在就直接注册了
		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 是个挺有意思的工具类,它主要的作用就是负责注册这些 AbstractAutoProxyCreator

  • 它给 InfrastructureAdvisorAutoProxyCreator AspectJAwareAdvisorAutoProxyCreator AnnotationAwareAspectJAutoProxyCreator 从低到高排了等级
  • 当它注册对应的实例时,会先从容器中查看是否存在当前实例,如果存在且等级比当前实例低,则会进行覆盖
  • 因此,此处注册的是最高等级的 AnnotationAwareAspectJAutoProxyCreator,它会覆盖容器中存在的其他实例,比如 Spring Cache 引入的 InfrastructureAdvisorAutoProxyCreator
  • 至此,Spring AOP 就实现了,跟我们上一章节末尾的示例差不多

原理解读

现在基于一段 Spring AOP 示例来重温一下整个流程

示例demo

@Configuration
@EnableAspectJAutoProxy
public class SpringAopDemo {

    @Aspect
    @Component
    public static class MyAspect {

        @Pointcut("execution(* com.example.springdemoall.aop.aop..*.hello())")
        public void pointcut() {}

        @Before("pointcut()")
        public void before() {
            System.out.println("before");
        }
    }

    public interface Hello {
        void hello();
    }

    @Component
    public static class HelloImpl implements Hello {
        @Override
        public void hello() {
            System.out.println("hello");
        }
    }

    @Test
    public void test() {
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(SpringAopDemo.class);
        Hello bean = context.getBean(Hello.class);
        bean.hello();
    }
}

流程解析

  1. 因为 @EnableAspectJAutoProxy 注解,容器中注册了 AnnotationAwareAspectJAutoProxyCreator 实例
  2. 它作为一个 AbstractAutoProxyCreator,在 HelloImplbean 实例生命周期阶段对它进行代理
  3. 作为一个 AbstractAdvisorAutoProxyCreator,它会收集容器中的 Advisors,同时作为 AspectJAwareAdvisorAutoProxyCreator 它会解析我们定义的切面为 Advisors(这部分工作由 ReflectiveAspectJAdvisorFactory 完成),这些 Advisors 会交给 ProxyFactory 来创建代理对象
  4. ProxyFactory 会基于代理配置选择对应的代理创建器,比如 JdkDynamicAopProxyObjenesisCglibAopProxy,在本例中是 JdkDynamicAopProxy
  5. JdkDynamicAopProxy 它本身就是个 InvocationHandler,因此代理后的方法调用为 invoke,在 invoke 方法中 JdkDynamicAopProxy 会基于之前获取的 Advisors (在本例中即我们基于切面解析的),获取当前方法匹配的 Interceptors Chain,封装成 ReflectiveMethodInvocation,最终通过 ReflectiveMethodInvocation#proceedMethodInterceptor#invoke 完成巧妙递归执行完所有拦截通知
  6. ObjenesisCglibAopProxyCGLIB 也是差不多一样的原理

总结

大体上的原理了解的差不多了,Spring AOP 作为 Spring 的核心特征之一,自然不是十几篇文章就能了解清楚的,但基于这些内容也能略知一二,无论是代码结构抽象设计上的学习、还是日常使用排错的学习,都是很有帮助的

上一篇:【源码】Spring AOP 13 原理解读二

参考

【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值