原理/源码分析
从Spring的@EnableXXX设计模式我们知道,源头就是@EnableAspectJAutoProxy这个注解,下面先来看看它做了什么
@EnableAspectJAutoProxy注解分析
//Enables support for handling components marked with AspectJ's {@code @Aspect} annotation, //similar to functionality found in Spring's {@code <aop:aspectj-autoproxy>} XML element. //Note: {@code @EnableAspectJAutoProxy} applies to its local application context only,(说明此注解只会作用于本容器,对子、父容器是无效得) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { // 决定该类采用CGLIB代理还是使用JDK的动态代理(需要实现接口),默认为false,表示使用的是JDK得动态代理技术 boolean proxyTargetClass() default false; // @since 4.3.1 代理的暴露方式:解决内部调用不能使用代理的场景 默认为false表示不处理 // true:这个代理就可以通过AopContext.currentProxy()获得这个代理对象的一个副本(ThreadLocal里面),从而我们可以很方便得在Spring框架上下文中拿到当前代理对象(处理事务时很方便) // 必须为true才能调用AopContext得方法,否则报错:Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available. boolean exposeProxy() default false; }
当然,最重点的,还是这一句@Import(AspectJAutoProxyRegistrar.class)
,下面看看它
AspectJAutoProxyRegistrar
:为容器注册 自动代理创舰器
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //这部非常重要,就是去注册了一个基于注解的自动代理创建器(如国需要的话) 当然,下面还会着重分析 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { // 若为true,表示强制指定了要使用CGLIB,那就强制告知到时候使用CGLIB的动态代理方式 if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 告知,强制暴露Bean的代理对象到AopContext if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
再来一个具相得认识:
我们发现当我们开启Spring AOP功能的时候,它只为我们向容器里加入了一个基础Bean~,也就是这个自动代理创建器
注册自动代理创建器AutoProxyCreator(AnnotationAwareAspectJAutoProxyCreator
)
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source); } public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source); } private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { // 很显然,这里如果我们自己定义了这样一个自动代理创建器,也是Ok的 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 如果我们自定义的并不是cls这个class类型的Bean,那就做如下处理一下 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { // 这个处理非常有意思,总之就是`InfrastructureAdvisorAutoProxyCreator`/AspectJAwareAdvisorAutoProxyCreator/AnnotationAwareAspectJAutoProxyCreator的一个逻辑~~~~(就是防止怕用户注册错了,做了一个容错处理~~~) int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); // currentPriority < requiredPriority 如果当前用户注册进来的Aop代理类的级别,是低于我们要求的级别的,Spring内部也会对它进行提升成我们要求的那个class类型 // 这样我符合我们的建议:最好不要自己去使用低级别的自动代理创建器 if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 若用户自己没有定义,那就用系统定义好的吧 AnnotationAwareAspectJAutoProxyCreator RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); // 此处注意,增加了一个属性:最高优先级执行 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); // 角色为Spring自己使用 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 注册此Bean定义信息 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; } //findPriorityForClass这个方法非常有意思:相当于找到index角标,然后 //APC_PRIORITY_LIST 的内容是下面这几个 按照顺序排好的 private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(); static { APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); }
这样一来,我们就成功的注入了一个Bean:AnnotationAwareAspectJAutoProxyCreator 基于注解的自动代理创建器
此处有个细节我们应该发现:应尽量避免自己创建AutoProxyCreator,而是统一交给Spring来智能处理。至于为何?后面会有专文分析利与弊~~~
AnnotationAwareAspectJAutoProxyCreator:自动代理创建器(AOP自动代理的核心)
由于介绍此创建器得篇幅颇长,因此我把它放在了此处单独成文进行介绍,请务必移步查看:
【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)
总结
本篇探讨了AOP的编程思想、过程,其主要思想是让开发者把诸多业务流程中的通用功能抽取出来,单独编写功能代码,形成独立的模块,这些模块也被称为切面。在业务流程执行过程中,Spring框架会根据业务流程要求,自动把切面切入到流程的合适位置