前言
最近看了《从零开始写JavaWeb框架》,想比较一下Spring AOP的实现方式和书的上实现方式有什么不同,所以先把Spring AOP的源码读一下,再进行比较。
Spring的源码实在是复杂,在读的过程中参考了很多书和网上的文章,本文算是这些文章的总结,再加上一些我自己对另个细节的理解。
本文分成 3 部分:
- 程序入口
- 切面和增强的取得
- 代理的生成
一,注册AspectJAnnotationAutoProxyCreator
如果使用
标签来自动生成代理的话,入口程序是AopNamespaceHandler
。在AopNamespaceHandler
中,下面一段代码是对
标签执行的调用:
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
AspectJAutoProxyBeanDefinitionParser解析器中,首先调用的parse方法。parse方法中有一行代码:
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
我们看一下registerAspectJAnnotationAutoProxyCreatorIfNecessary
方法的实际内容:
public static void registerAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册或更新 AutoProxyCreator 定义 beanName 为 org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
// 如果internalAutoProxyCreator的BeanDefinition已经存在,而根据优先级更新BeanDefinition
// 在这里我们注册的是AnnotationAwareAspectJAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 对于 proxy-target-class 以及 expose-proxy 属性的处理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册组件并通知,便于监听器作进一步处理
// 其中 beanDefinition 的 className 为 AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
那为什么注册AnnotationAwareAspectJAutoProxyCreator,注册AnnotationAwareAspectJAutoProxyCreator有什么用呢?
其实,实现AOP处理是其实是通过BeanPostProcessor机制实现的。AnnotationAwareAspectJAutoProxyCreator的父类也实现一个BeanPostProcessor类型的接口,而生成代理的逻辑就在AnnotationAwareAspectJAutoProxyCreator的BeanPostProcessor接口实现里面。
更严谨地说,AnnotationAwareAspectJAutoProxyCreator
的父类实现的接口是
SmartInstantiationAwareBeanPostProcessor
,主要是Spring框架内部使用的一个接口。而这个接口的父接口InstantiationAwareBeanPostProcessor
是实现代理的重点之一。
这3个接口的关系如下:
SmartInstantiationAwareBeanPostProcessor -> InstantiationAwareBeanPostProcessor -> BeanPostProcessor
为什么说是是InstantiationAwareBeanPostProcessor
接口的子接口,接口是重点之一?那InstantiationAwareBeanPostProcessor
接口是什么接口呢?
BeanPostProcessor
主要作用于Bean
实例化后,初始化前后。InstantiationAwareBeanPostProcessor
虽然是BeanPostProcessor
的子接口,但它的调用时间点其发生在Bean实例化前,在真正调用doCreate()
创建bean实例之前。
在创建Bean
实例之前,会先调用resolveBeforeInstantiation
方法,这个方法是生成Bean
代理的地方。如果此方法返回值不为空则直接返回生成的Bean
的代理,如果为空就向下走正常的Bean
生成流程。
spring注释“Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. ”给BeanPostProcessors一个机会返回代理proxy对象。
而InstantiationAwareBeanPostProcessor
接口方法,就是在resolveBeforeInstantiation
方法中调用的。所以可以看出,BeanPostProcessore
有很多,但Spring AOP的实现就是通过InstantiationAwareBeanPostProcessor
这个BeanPostProcessor
实现的。看一下源码:
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
......
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 如果返回值不为空,说明生成成了此BeanName的代理,直接返回代理对象
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
......
}
// 如果没有生成代理对象,就按正常流程走,生成Bean对象
Object beanInstance = doCreateBean(beanName, mbd, args);
.....
return beanInstance;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 调用InstantiationAwareBeanPostProcessor接口的地方
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class> beanClass, String beanName)
throws BeansException {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 转换成InstantiationAwareBeanPostProcessor接口,并调用
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
顺带说一下,注册AnnotationAwareAspectJAutoProxyCreator的目的是:把这个类的BeanDefinition通过registerBeanDefinition方法(DefaultListableBeanFactory类中)加入到beanDefinitionMap中,作为一个Bean让Spring管理,这样Spring就可以随意取得它了。
如果使用
标签来自动生成代理的话,入口程序是AopNamespaceHandler
。那AopNamespaceHandler
是在什么地方被调用的呢?
这个问题让我们从容器启动的地方开始说明。以FileSystemXmlApplicationContext
为例,这个类的入口是构造函数里面的refresh()
方法。从refresh()
方法开始,调用流程是这样的:(以下流程全部是嵌套调用的关系)
1. refresh() ->
刷新容器
2. obtainFreshBeanFactory() ->
获得刷新后的Bean容器
3. refreshBeanFactory() ->
刷新Bean容器
4. loadBeanDefinitions() ->
加载BeanDefinition
5. XmlBeanDefinitionReader#loadBeanDefinitions
新建一个XmlBeanDefinitionReader实例(new XmlBeanDefinitionReader(beanFactory)),调用这个实例的loadBeanDefinitions方法。
6. XmlBeanDefinitionReader#doLoadBeanDefinitions
7. XmlBeanDefinitionReader#registerBeanDefinitions
8. XmlBeanDefinitionReader#createBeanDefinitionDocumentReader
在这个方法中取得了DefaultBeanDefinitionDocumentReader实例。接下来调用这个实例的方法。
9. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
在这个方法中,根据URI判断是否使用AopNamespaceHandler
10. DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
从registerBeanDefinitions方法开始,内部连续调用一系列方法,一直调用到parseBeanDefinitions方法。在这个方法中,根据XML文件的URI判断使用哪些解析器,例如是类标签解析器,还是类标签解析器。
如果是需要标签解析器的话,在this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)代码中,从配置文件(spring.handlers)从取出AopNamespaceHandler的类名,生成这个类的实例,然后调用这个类的parse方法。
11. AopNamespaceHandler#parse
这个方法的功能是,根据具体标签调用具体解析器的parse方法。
- :AspectJAutoProxyBeanDefinitionParser
- :ConfigBeanDefinitionParser
等。
这个方法的调用,又回到了我们最初讲的AopNamespaceHandler入口的地方。
到此为止,从容器到AopNamespaceHandler类调用的过程也讲完了。
二,AspectJAnnotationAutoProxyCreator的流程
通过上面的内容,我们知道了注册AnnotationAwareAspectJAutoProxyCreator
的意义,并且知道了生成代理是在它的BeanPostProcessor
接口里做的,现在看看被实现的接口的内容。(postProcessAfterInitialization 具体实现是在其父类 AbstractAutoProxyCreator 中完成的):
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
// 根据给定的 bean 的 class 和 name 构建出个 key,格式:beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果它适合被代理,则需要封装指定 bean。
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 是否已经处理过
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 无需增强
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 给定的 bean 类是否代表一个基础设施类,基础设施类不应代理,或者配置了指定 bean 不需要自动代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 如果存在增强方法则创建代理(*重要*)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果获取到了增强则需要针对增强创建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理(*重要*)
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
这里有两个方法特别重要:
- getAdvicesAndAdvisorsForBean:如果Bean是要被代理的对象的话,取得Bean相关的Interceptor
- createProxy:创建代理
下一篇文章,我们就这两个方法的下面的流程分开来分析一下,首先分析getAdvicesAndAdvisorsForBean
相关代码。
关于接口实现的补充:
AnnotationAwareAspectJAutoProxyCreator
一共实现了2个BeanPostProcessor
的接口,的4个方法:
- postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor)
- postProcessAfterInstantiation(InstantiationAwareBeanPostProcessor)
- postProcessBeforeInitialization(BeanPostProcessor)
- postProcessAfterInitialization(BeanPostProcessor)
postProcessBeforeInstantiation
(InstantiationAwareBeanPostProcessor
接口)方法中,这个方法是在AnnotationAwareAspectJAutoProxyCreator
的基类AbstractAutoProxyCreator
中实现的。细看一下,在postProcessAfterInitialization
方法中也有类似的生成代理的代码。这是为什么呢?
上网找了一些资料,在postProcessBeforeInstantiation
方法中有一个判断:
如果某个
Bean
设置了自定义TargetSource
的话,就在本方法中进行生成代理而
postProcessAfterInitialization
则没有这样的判断,只是在生成代理前判断了一下代理是否已经生成。具体为什么有这样的必须还不清楚(以后有需要调查一下),但结果就是:
- 如果
Bean
设置了自定义TargetSource
,就在postProcessBeforeInstantiation
中生成代理 - 如果没有,就在
postProcessAfterInitialization
中生成代理。
最后,不管理在哪个方法里生成代理,在创建每个Bean时都会被调用这两个方法,代理的生成逻辑就是在这两个方法中实现的。
关于TargetSource:spring-aop组件详解——TargetSource目标源
关于自定义TargetSource:《Spring揭密》的9.6章节