最近在学习Spring AOP,就顺便看了一下Spring AOP的源码,这里记录一下,防止七秒钟的记忆。之前写过一篇关于Spring AOP的基本使用:Spring AOP 基本概念和使用,建议大家先去观看一下,再回来阅读这篇文章。
AOP是一种思想和理念,可以使用这种思想来简化代码开发的耦合性和难度,有句话说的好,天上飞的理念,必有落地的实现,那么实现了AOP这个思想的具体实现由Spring AOP和AspectJ技术,他们都是根据AOP的思想实现的。
Spring AOP和AspectJ的关系?
springAop、AspectJ都是Aop的实现,Spring AOP使用XML的格式进行配置的,SpringAop有自己的语法,但是语法复杂,所以SpringAop借助了AspectJ的注解(记住只是使用到了AspectJ的注解,而进行注解的解析工作是Spring内部实现的,所以Spring AOP只是借助了AspectJ的注解而已)。
spring AOP提供两种编程风格
@AspectJ support ------------>利用aspectj的注解
Schema-based AOP support ----------->xml aop:config 命名空间
证明:spring通过源码分析,我们可以知道spring底层使用的是JDK或者CGLIB来完成的代理,并且在官网上spring给出了aspectj的文档,和springAOP是不同的
关于Spring AOP的使用,Spring官网是推荐使用AspectJ来进行的,这里的源码分析也是分析基于注解使用的Spring AOP。
要能够使用AspectJ的注解,首先需要在配置上面添加@EnableAspectJAutoProxy,来增加对注解的解析,首先来看一下这个@EnableAspectJAutoProxy的源码。
代码块1:@EnableAspectJAutoProxy源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
可以看到EnableAspectJAutoProxy注解上面有使用@Import向容器中导入了bean,这里就牵涉到@Import的使用了,感兴趣的同学可以参考:Spring为IOC容器注入Bean的方式,这里使用的是@Import + ImportBeanDefinitionRegistrar的方式向Spring容器中注入bean,下面看一下AspectJAutoProxyRegistrar的源码。
代码块2:AspectJAutoProxyRegistrar源码
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//1.注册AnnotationAwareAspectJAutoProxyCreator的BeanDefinition
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
//2.获取原注解也就是EnableAspectJAutoProxy上面设置的属性值
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
//3.设置proxyTargetClass属性
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
//4.设置exposeProxy属性
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
第1步注册一个AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,此步骤很关键,具体看代码块3中的registerAspectJAnnotationAutoProxyCreatorIfNecessary的源码,第2、3、4步就是向AnnotationAwareAspectJAutoProxyCreator的BeanDefinition设置属性的步骤,看一下第3步和第四步设置proxyTargetClass属性和设置exposeProxy属性,具体看代码块5。
代码块3:AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
//1
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
//2.这里传入AnnotationAwareAspectJAutoProxyCreator.class,也就是将这个类封装成BeanDefinition对象
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
//3.判断是否保存了AUTO_PROXY_CREATOR_BEAN_NAME这个BeanDefinition
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
//4.走到这,说明容器中存在这个BeanDefinition,判断从容器中获取的这个BeanClassName和AnnotationAwareAspectJAutoProxyCreator.class
//这个名称是否相同
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
//5.如果名称不一样,则获取优先级,在这里我们知道cls传过来的是AnnotationAwareAspectJAutoProxyCreator这个类,
//而这个AnnotationAwareAspectJAutoProxyCreator的优先级是最高的,如果名称不一样,则BeanClassName则会被替换成
//AnnotationAwareAspectJAutoProxyCreator.class的名称
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//6.走到这,说明容器中没有AUTO_PROXY_CREATOR_BEAN_NAME这个BeanDefinition,下面就是创建这个BeanDefinition
//然后放到容器中
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//7.往容器中注入这个BeanDefinition
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
第3步,判断容器中是否包含封装了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition对象,如果不包含,则直接往容器里面注入一个封装了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition对象,如果包含则判断名称是否相同,如果不相同,获取其优先级,我们知道cls传过来的是AnnotationAwareAspectJAutoProxyCreator这个类,这个类的优先级最高,具体可以看代码块4。对于为什么要封装成BeanDefinition对象,因为在Spring创建bean时,是根据BeanDefinition对象来创建对象的,关于BeanDefinition可以查看:Spring中bean的生命周期(最详细),里面有说到Spring创建bean的大致流程。
代码块4:AopConfigUtils#findPriorityForClass
/**
* Stores the auto proxy creator classes in escalation order.
*/
private static final List> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
private static int findPriorityForClass(Class> clazz) {
//1.获取其所在数组的下标值,如果没有这个clazz,则会返回-1
return APC_PRIORITY_LIST.indexOf(clazz);
}
代码块5:AopConfigUtils#forceAutoProxyCreatorToUseClassProxying
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
//1.如果容器中包含AUTO_PROXY_CREATOR_BEAN_NAME的BeanDefinition,则设置proxyTargetClass属性为true,
//该属性在创建动态代理的时候,会影响使用JDK还是CGLIB来实现动态代理
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
如果容器中包含AUTO_PROXY_CREATOR_BEAN_NAME的BeanDefinition,则设置proxyTargetClass属性为true,该属性在创建动态代理的时候,会影响使用JDK还是CGLIB来实现动态代理,这个到后面再详细说明。
到此就完成了向Spring容器中注入了一个封装了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition对象,那么这一步什么时候执行呢?我这里大致说一下:
一: Spring在执行流程中,有一步会执行invokeBeanFactoryPostProcessors,在此步骤会调用所有的BeanFactoryPostProcessors的实现类,也就是在这一步,循环递归的方式,将Spring项目中所有的需要导入的Spring容器的对象都封装成BeanDefinition对象,注意,这一步会扫描bean上面的注解,然后进行解析,将AnnotationAwareAspectJAutoProxyCreator封装成BeanDefinition的步骤也会在此随着解析@EnableAspectJAutoProxy而导入到容器中。
上图是AnnotationAwareAspectJAutoProxyCreator的继承关系,可以得知AnnotationAwareAspectJAutoProxyCreator是一个一个bean的后置处理器,而且实现了BeanClassLoaderAware、BeanFactoryAware接口,可以拿到类加载器和bean工厂对象,这个对于后期创建动态代理是很有必要的,而对于bean的后置处理器,可以查看:Spring中bean的生命周期(最详细),这里面会详细的介绍所有的bean的后置处理器的执行时机和作用,会在普通bean实例话之前执行创建bean,会在Spring主流程的registerBeanPostProcessors方法中创建出bean,然后这个BeanPostProcessor会在所有的普通的bean创建时起作用,这样的话,在我们使用了AspectJ注解来完成AOP代理时,在Spring执行流程中AnnotationAwareAspectJAutoProxyCreator这个bean的后置处理器就会起作用。
关于AnnotationAwareAspectJAutoProxyCreator的创建已经说完了,下篇将介绍普通bean创建时AnnotationAwareAspectJAutoProxyCreator的bean后置处理器起到的作用。