Spring源码分析 —— AOP原理

回顾一下我们说过Spring bean的生命周期主要大概有以下几个步骤:

  • 创建bean的实例
  • 给实例化出来的bean填充属性
  • 初始化bean
  • 通过IOC容器使用bean
  • 容器关闭时销毁bean

之前我们已经就前两部分做了比较详尽的分析。

本文想要跟大家分享的是Spring中非常重要的概念——AOP。AOP确切发生的步骤是在第三步初始化bean中的某一步,请注意本文还没有把所有bean初始化的步骤说完,但Spring AOP无论在日常工作中,还是在面试中都是比较重要的概念,所以单独给它分析一下。

AOP和Spring AOP

这里需要说明一件事:AOP不是Spring特有的,AOP跟OOP一样,是一种理念,是将纵向的业务流程中的一些水平功能(日志记录等)逻辑单独拎出来做处理,从而减少这些必要但非核心业务逻辑的耦合,增强程序员对业务逻辑的关注。只不过Spring提供了一种AOP的实现,叫做Spring AOP。

同样,IOC也不是Spring特有的,IOC是一种控制反转理念,将对象的初始化交给容器或者说框架本身来做,程序员开始上手只需要拿这个instance就可以了。Spring IOC也只是Spring提供的IOC理念的实现。

Spring AOP的用法以及各种术语(切面、连接点、切点、织入等)不是本文要纠结的重点,如果还不清楚基本用法的建议读到这里可以右上角x掉了。

回顾doCreateBean()

我们在分析bean生命周期的前两步的时候,都走到doCreateBean()这个方法,然后分流了。还记得这个方法大体上分3步吗:

1
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
33
34
35
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//第一步 创建bean实例,还未进行属性填充和各种特性的初始化
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();

// Initialize the bean instance.
Object exposedObject = bean;
try {
// 第二步 进行属性填充(依赖注入)
populateBean(beanName, mbd, instanceWrapper);
// 第三步 执行bean的初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
// 抛相应异常
}

// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

第一步,根据扫描出来的BeanDefinition推断出来的构造方法,然后反射来创建实例。

第二步,根据扫描出来的所有带有@Autowire标签的依赖实例,进行依赖注入。

第三步,bean初始化,我们的AOP功能就在这里实现,除了AOP之外,还有一系列的postProcessor在此被调用,完成各种bean增强。

前面的过程都一样了,我们就从doCreateBean()开始吧。

Spring AOP源码

Spring AOP创建入口

在上面第三步中,我们点进initializeBean()方法(省略了非必要代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 对于非空的beanDefinition,并且是用户定义的bd
// 调用init之前的后置处理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// 调用自定义的init方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
// 处理异常
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用init之后的后置处理器
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

所以在bean初始化时,大体分为3步:

  1. 调用init之前的postProcessor;
  2. 做初始化;
  3. 调用init之后的postProcessor。

这里只需要了解postProcessor有很多种,包括Spring自身提供的,和程序员对Spring做扩展自己写的。这些postProcessor会存在BeanFactory的一个COW的List里面,你可以自定义一个postProcessor,并且重写它的postProcessBeforeInitialization()和postProcessAfterInitialization()方法来对Spring进行扩展。

Spring AOP发生在第3步,也就是bean完成了初始化之后调用的postProcessor。

applyBeanPostProcessorsAfterInitialization()

这个方法是抽象BeanFactory中提供的方法,主要就是拿到所有的postProcessor,并且迭代调用它的postProcessAfterInitialization()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {

Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

Spring AOP使用的postProcessor是AbstractAutoProxyCreator提供的,从它的Class定义也可以看出来它是一个postProcessor(implements):

1
2
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

所以这个AbstractAutoProxyCreator重写的postProcessAfterInitialization()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// cacheKey可以简单理解就是beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// earlyProxyReferences是用来解决循环依赖的
// AOP的简单流程不涉及循环依赖,所以会进这个if
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

wrapIfNecessary()

1
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
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 一些不用代理的返回
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// Create proxy if we have advice.
// 创建AOP代理的逻辑
// 1. 拿到所有定义的advice,这个我们在pointCut已经定义过了
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 2. 创建代理,两种方式:jdk动态代理和cglib
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;
}

所以这里主要有2步:

  1. 拿到所有的advice通知 - getAdvicesAndAdvisorsForBean();
  2. 根据拿到的advice通知方法,createProxy()创建代理进行bean的AOP增强。

getAdvicesAndAdvisorsForBean()

1
2
3
4
5
6
7
8
9
10
11
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 这里只需要知道找到了所有定义的advisor就可以了
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}

这里需要说一下Advisor是怎么工作的,为啥有的advice就能做前置增强,有的就可以做后置,而有的可以做环绕增强呢?

首先说Advisor有非常多的子类实现,每个子类都封装了一个Advice的成员变量;这个Advice是一个接口,也有非常多的实现类,我们就拿AspectJAfterAdvice这个Advice的实现类来举例吧,它是AspectJ风格的后置增强实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}

}

它在重写的invoke()方法时,先去做proceed()调用Invocation对象自身定义的method(),然后在finally中实现的advice后置增强,代码的执行顺序也是保证了finally块中一定在proceed()执行完(无论是否正常退出)之后进行后置advice。

所以实际上我们在给Spring AOP准备Advisor数组时,做好封装并且拿到数组,然后传给下面创建的代理就可以实现各种增强了。

createProxy()

我们在各种地方都可以看到这么一段话:Spring AOP咋实现的?答通过代理。有几种代理方法?答jdk动态代理和cglib代理。这几乎是地球人都知道的一个层面,那它在源码上是如何体现的?

1
2
3
4
5
6
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();

return proxyFactory.getProxy(getProxyClassLoader());
}

省略了不必要的代码之后,它就做了2件事:

  1. 创建了一个proxyFactory;
  2. 通过这个proxyFactory去拿代理(创建代理对象)。

中间还有几个简单的调用,我们可以直接来到最下面一层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
// 如果代理类是接口,或者它本身就是一个代理对象
// 按照常识也使用jdk动态代理
return new JdkDynamicAopProxy(config);
}
// 否则的话使用cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

看吧,经典的2种代理就是在这里体现的。

创建AOP代理后返回的实例

我这里做实验搞了一个最简单的增强bean,它是普通的类(不是接口),开debug模式可以看到,在createProxy()之后,Spring给我返回的是这么一个类:

proxy_enhancer_by_cglib

放大看看:

details

后面给我加了$$EnhancerBySpringCGLIB$$xxxxx,事实上,在Context完成初始化之后,我拿到的bean也是这么一个东西:

AOP_in_main

总结

本文只是把bean初始化中的AOP部分分析了一遍,这个过程中还有其他的一些步骤,主要是各个postProcessor来完成的,所以读者可以从几方面扩展一下:

  1. 其他的postProcessor和哪些Spring其他的功能相关联,可以自行debug看一下源码;
  2. 能不能对Spring做一些扩展,也就是自己写一个postProcessor呢?
  3. 自己写的postProcessor在哪一步被装载进Spring,又在哪里执行的?