AOP
提示
本篇用于记录Spring-AOP的源码解析,讲解AOP核心类:AnnotationAwareAspectJAutoProxyCreator类如何注册到Spring中,并解析到SpringIOC的
# 1. AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator实现了AOP逻辑
我们通过以下配置可以让Spring自动完成对AnnotationAwareAspectJAutoProxyCreator类的注册,从而实现AOP的功能。
<aop:aspectj-autoproxy/>
在讲解AnnotationAwareAspectJAutoProxyCreator功能之前,先得知道它是怎么被注册到Spring中,并如何被解析到SringIOC中的?下面来看看Spring是如何注册AnnotationAwareAspectJAutoProxyCreator这个类。
# 2. Spring注册AnnotationAwareAspectJAutoProxyCreator
说到Spring注册AnnotationAwareAspectJAutoProxyCreator,那要从SpringIOC加载META-INF/spring.handlers说起了。SpringIOC在初始化时,不仅从XML中获取了bean的定义信息,还从classpath下的META-INF/spring.handlers中获取到对应的Handler,可以从spring-aop的jar包中查看到该文件,文件内容如下:
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
# 2.1 AopNamespaceHandler
Springd通过DefaultNamepsaceHandlerResolver类的getHandlerMappings()方法上将配置文件中的xmlns配置都解析成了一个Java命名解析器(NamespaceHandler)
public class AopNamespaceHandler extends NamespaceHandlerSupport {
public AopNamespaceHandler() {
}
public void init() {
this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
// 1. 注册入口
this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
2
3
4
5
6
7
8
9
10
11
可以看到,在init()方法里,Spring对aspectj-autoproxy也就是AnnotationAwareAspectJAutoProxyCreator进行了注册
# 2.2 AspectJAutoProxyBeanDefinitionParser
调用AspectJAutoProxyBeanDefinitionParser类中的parse方法
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
// 2. 解析入口为parse方法
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
}
2
3
4
5
6
7
8
在Spring中,所有的解析器都是对BeanDefinitionParser接口的同一实现,解析入口都是从parse方法开始的
# 2.3 AopNamespaceUtils
调用类中的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,获得BeanDefinition和一些配置信息
public abstract class AopNamespaceUtils {
public static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";
...
// 3. 获取BeanDefinition和一些配置信息
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
//把应用了@Aspect注解修饰的bean注册成BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//处理proxy-target-class和expose-proxy属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
//注册组件并通知解析器
registerComponentIfNecessary(beanDefinition, parserContext);
}
2
3
4
5
6
7
8
9
10
11
12
13
# 2.4 AopConfigUtils
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法其实是调用了该类的registerOrEscalateApcAsRequired方法
public abstract class AopConfigUtils {
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
} else {
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", -2147483648);
beanDefinition.setRole(2);
registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
return beanDefinition;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
registerOrEscalateApcAsRequired方法的作用就是获取AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,然后根据优先级来装配这个BeanDefinition。
获取到了AnnotationAwareAspectJAutoProxyCreator之后,接下来就要将配置信息和BeanDefinition一起注册到SpringIOC中。
无图无真相,可以看到registerAspectJAnnotationAutoProxyCreatorIfNecessary方法返回的beanDefinition
# 2.5 proxy-target-class和expose-proxy属性
如果proxy-target-class和expose-proxy都为true时,代码的逻辑
public abstract class AopConfigUtils {
...
/*
* 如果proxy-target-class为true,则走该方法的逻辑
*/
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
/*
* 如果expose-proxy为true,则走该方法的逻辑
*/
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
把bean的定义信息存放到了BeanDefinition中,Spring将设置的proxyTargetClass和exposeProxy的值存放到了BeanDefinition的PropertyValues里。
# 2.6 registerComponentIfNecessary
//把应用了@Aspect注解修饰的bean注册成BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//处理proxy-target-class和expose-proxy属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
//注册组件并通知解析器
registerComponentIfNecessary(beanDefinition, parserContext);
2
3
4
5
6
经过了useClassProxyingIfNecessary()方法的调用,ParserContext对象中存放好了注册的额外信息(proxy-target-class、expose-proxy值等),这里暂且将ParserContext称为解析上下文。
由上面的源码2.3节可知,在AopNamespaceUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中,将获取的org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition和解析上下文一起传入registerComponentIfNecessary方法中,进行Component组件注册。
public abstract class AopNamespaceUtils {
...
private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
if (beanDefinition != null) {
parserContext.registerComponent(new BeanComponentDefinition(beanDefinition, "org.springframework.aop.config.internalAutoProxyCreator"));
}
}
}
2
3
4
5
6
7
8
9
在随后的registerComponentIfNecessary方法中,经过new BeanComponentDefinition()构造方法的调用,已经将AnnotationAwareAspectJAutoProxyCreator的BeanDefinition注册到了SpringIOC中,存放在解析上下文(ParserContext)中。
解析上下文存放在SpringIOC(ApplicationContext,又称为Spring应用容器上下文)中
最后,在AspectJAutoProxyBeanDefinitionParser类的extendBeanDefinition方法中取出。
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
2
private void extendBeanDefinition(Element element, ParserContext parserContext) {
BeanDefinition beanDef =
parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
if (element.hasChildNodes()) {
addIncludePatterns(element, parserContext, beanDef);
}
}
2
3
4
5
6
7
# 3. 小结
- aop:aspectj-autoproxy/的作用是在Spring中注册AnnotationAwareAspectJAutoProxyCreator
- 注册之后的解析工作是由AspectJAutoProxyBeanDefinitionParser类的.parse方法完成的
- aop:aspectj-autoproxy/的proxy-target-class和expose-proxy属性会被注册到BeanDefinition的PropertyValues里
- proxy-target-class的作用:
- 强制使用CGLIB,配置如下属性即可使用CGLIB
<aop:config proxy-target-class="true"/>
- 使用CGLIB代理和@AspectJ自动代理支持,配置如下配置即可实现
<aop:aspectj-autoproxy proxy-target-class="true"/>
- expose-proxy的作用:用于那种在在内部调用方法时无法调用切面逻辑的一种强制通知