本文重点分析 Spring AOP 实践一文中,通过ProxyFactoryBean手动配置动态代理的实现原理。
原理分析将基于以下示例代码。
1 | public class UserService { |
1 |
|
从启动入口开始分析
1 | public class CodingInActionApplication{ |
1.ProxyFactoryBean 实例化
1 | new ClassPathXmlApplicationContext("applicationContext.xml") |
该行代码对应Spring IOC 容器的启动过程
如图中所示,应用上下文启动后,IOC 容器 beanFactory 需要初始化5个bean, 都是在XML 文件中定义的数据,其实前4个都是我们非常熟悉的普通业务bean。userServiceProxy 是配置的ProxyFactoryBean, 当实例化userServiceProxy时,与常见流程略有不同,主要是以下2点
1.1 isFactoryBean
userServiceProxy会在isFactoryBean 判断中结果为true, 需要加上FactoryBean 前缀 & 后才开始进行实例化,
在介绍FactoryBean时,已经提到 FactoryBean也是一个bean , 所以在IOC 容器启动过程中,也会进行实例化
针对一个FactoryBean
- 使用
getBean("&beanName")可以获取FactoryBean实例本身,而不是FactoryBean创建的对象。 - 使用
getBean("beanName")则获取由FactoryBean创建的对象。
基于以上2点,我们可以得到,在IOC 容器启动,实例化bean的过程中, 经过getBean(“&userServiceProxy”), 最终放入IOC 容器中的userServiceProxy 这个 FactoryBean本身。
1.2 getObjectForBeanInstance
进入我们应该非常熟悉的getBean 流程
这是IOC 容器在进行bean 的初始化流程,对于userServiceProxy 来讲,此时三级缓存中肯定不存在它的缓存, 所以会进入到单例bean 的创建流程,创建流程就不进去细看了,可以去参考文章Spring bean 实例化。只重点看getObjectForBeanInstance的处理逻辑 。
在Spring bean 实例化一文中重点讲过的用于处理FactoryBean 的getObjectForBeanInstance 方法, getBean 方法传入的参数name 是&userServiceProxy, 说明经过getObjectForBeanInstance 方法处理后,最终返回了FactoryBean 本身, 在这次debug 过程中,即是ProxyFactoryBean
2.创建动态代理对象-FactoryBean.getObject
Spring IOC 容器启动完成后,就可以从容器中获取需要的bean 了1
UserService userService = (UserService) context.getBean("userServiceProxy");
由于userServiceProxy 是FactoryBean, 现在执行getBean("userServiceProxy"), 说明需要获取由它创建的动态代理对象
2.1 getObjectForBeanInstance
进入源码,再次来到getBean 流程,
此时getSingleton,一级缓存中已经有了IOC 容器启动过程的中创建userServiceProxy实例, 直接获取即可。再次进入getObjectForBeanInstance 方法
2.2 FactoryBean.getObject
在getObjectForBeanInstance 方法中, 逐层深入源码来到ProxyFactoryBean.getObject 方法。
实现 FactoryBean 接口的类,可以通过重写 getObject 方法来创建并返回实际的对象实例。
分析ProxyFactoryBean.getObject() ,主要代码可以分成2个步骤
- initializeAdvisorChain
- getSingletonInstance
2.3 initializeAdvisorChain
1 | private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { |
该方法的主要逻辑是根据配置的interceptorNames初始化AdvisorChain,确保在执行切面逻辑时,所有的Advisor和Interceptor都已正确配置和初始化。
AdvisorChain 就是一个List数据结构,存储根据interceptorName 获取对应实例1
advice = this.beanFactory.getBean(name);
对于单例bean来讲,就是从前面启动完成的IOC 容器中,根据name 通过getBean 方法取出对应的实例
2.4 getSingletonInstance
1 | public class ProxyFactoryBean extends ProxyCreatorSupport |
以上代码删除了部分细节,只保留重点逻辑
- createAopProxy: 确定动态代理的类型, JDK 动态代理 or CGlib, 判断的逻辑也非常简单,可以简单认为就是有没有实现接口
- 实现了接口,用JDK 动态代理
- 没有实现接口,用CGlib 动态代理
- getProxy:根据确定的动态代理,创建target 的代理对象
2.4.1 createAopProxy
确定动态代理的类型, JDK动态代理 or CGlib动态代理
关于动态代理,可以点击阅读Java 动态代理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
public class ProxyCreatorSupport extends AdvisedSupport {
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
}
// 确定动态代理的类型
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
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.");
}
// 判断目标类是否是接口。如果是接口,使用JDK动态代理。
// 如果是代理类,也使用JDK动态代理。
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 如果目标类既不是接口,也不是代理类,则使用CGLIB代理。
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
}
传进来的config 就是userServiceProxy 这个ProxyFactoryBean, 里面有各种信息,可以根据这些信息帮助判断动态代理的类型。
2.4.2 getProxy
advised 指的就是前面示例代码中配置的ProxyFactoryBean , 它的targetSource 是要被代理的userService
3.Cglib动态代理对象-CglibAopProxy
3.1 getProxy
1 |
|
3.2 ObjenesisCglibAopProxy
从2.4.1-createAopProxy 代码中可以看出,如果是cglib 动态代理,最终返回的是ObjenesisCglibAopProxy,而不是直接返回CglibAopProxy
在Spring AOP框架中,CglibAopProxy和ObjenesisCglibAopProxy都用于创建CGLIB代理,二者的区别与联系如下
- 实例化方式
- CglibAopProxy: 直接使用CGLIB库的
Enhancer类来创建代理类,通常会调用目标类的构造函数。 - ObjenesisCglibAopProxy: 利用Objenesis库来实例化代理对象,避免了直接调用目标类的构造函数,提供了一种更灵活的实例化方式。
- CglibAopProxy: 直接使用CGLIB库的
- 应用场景
- CglibAopProxy: 适用于一般的CGLIB代理场景,当目标类的构造函数没有特殊要求时,是Spring AOP的默认选择。
- ObjenesisCglibAopProxy: 适用于需要在不调用构造函数的情况下创建代理的场景,特别是当目标类的构造函数较为复杂或有特殊限制时,提供了一种更灵活的解决方案。
3.3 getCallbacks-自动实现 MethodInterceptor
在Java 动态代理一文, 关于 CGLIB 动态代理,我们手动实现了一个MethodInterceptor, 并将其设置为Enchaner的Callback
1 | public class HelloWorldInterceptor implements MethodInterceptor { |
3.3.1 Callback
1 | package org.springframework.cglib.proxy; |
Callback 是一个接口,MethodInterceptor 是其常用的实现之一。MethodInterceptor 其核心方法是 intercept,负责拦截代理对象的方法调用,应用相应的Advice 增强逻辑,并最终调用目标对象的方法。
3.3.2 MethodInceptor 在CglibAopProxy的实现
在此次XML 配置形式的AOP 中, 并没有手动实现MethodInceptor 的逻辑。 MethodInceptor 的具体实现 由CglibAopProxy 背后帮我们偷偷做了, 实现的逻辑这行代码中, 进去看下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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50Callback[] callbacks = getCallbacks(rootClass);
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
// 是否需要公开代理对象。
boolean exposeProxy = this.advised.isExposeProxy();
// 代理配置是否被冻结。
boolean isFrozen = this.advised.isFrozen();
// 目标源是否是静态的(即目标对象在创建时已经确定,不会变化)。
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
// 创建一个DynamicAdvisedInterceptor实例,用于处理AOP调用。这是主要的AOP拦截器。
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// Choose a "straight to target" interceptor. (used for calls that are
// unadvised but can return this). May be required to expose the proxy.
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
targetInterceptor = (isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice 处理常规的AOP增强。
// 优化情况下直接调用目标对象的方法。
targetInterceptor, // invoke target without considering advice, if optimized
// 对于没有增强的方法,什么也不做。
new SerializableNoOp(), // no override for methods mapped to this
// 直接调用静态目标的方法。
targetDispatcher,
// 代理配置的调度器。
this.advisedDispatcher,
// 处理equals方法的拦截器。
new EqualsInterceptor(this.advised),
// 处理equals方法的拦截器。
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
return callbacks;
}
省略了部分代码只看重点,可以看到最终返回的Callback数组中包含6个数据,其中包括多个MethodInceptor的实现类。提前看下创建完成的userService 实例debug 信息, Callback信息和代码中的数据是可以一一对应上的
MethodInterceptor 在CglibAopProxy 有多个实现,均已私有类的形式存在,下面重点分析一下DynamicAdvisedInterceptor,常规的AOP 增强逻辑的织入均是由它实现。
3.4 执行目标方法-DynamicAdvisedInterceptor.intercept
3. 4 方法执行-intercept
经过getProxy获取Cglib 动态代理对象后, 将通过代理对象执行业务逻辑1
2userService.createUser("john");
userService.deleteUser("john");
下面将跟随debug 信息来分析 代理对象方法的执行。
执行userService.createUser("john");
代码会来到CglibAopProxy中DynamicAdvisedInterceptor.intercept 方法
1 | private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { |
MethodIntercept.intercept, 在本示例中指的是具体实现类DynamicAdvisedInterceptor.intercept 是目标方法执行的拦截入口,拦截后,重点逻辑有2处
getInterceptorsAndDynamicInterceptionAdvice获取当前类当前方法上可用的advice,CglibMethodInvocation.proceed, 通过ReflectiveMethodInvocation.proceed递归Advice增强逻辑 和目标方法
3.4.1 getInterceptorsAndDynamicInterceptionAdvice
在增强逻辑和目标方法执行前,,需要先把Spring 容器中所有Advice 进行筛选,获取在当前类当前方法上可用的advice。
关于筛选逻辑,使用的是Advisor 、Pointcut 和Advice。
Advisor是一个复合概念,包括配套的Pointcut和Advice。Pointcut中包含了对类的过滤条件ClassFilter、方法的过滤条件MethodMatcherAdvice是符合Pointcut切点条件的方法上需要执行的增强逻辑。
看图中高亮的66行代码,就是我们在自定义的 LoggingAdvisor、LoggingPointcut重写的方法

最终可以用在UserService.createUser 上的Advice/Interceptor 有3个
- 一个自定义的
LoggingAdvisor - 2个直接定义的Advice,
LoggingBeforeAdvice、LoggingAfterAdvice, 它们会被处理成DefaulrPointcutAdvisor, 默认对所有类的所有方法均有效
当执行delete方法是,符合条件的interceptor 只有2个, 符合预期结果
缓存的应用
针对每个方法可用的advice 列表, 这里使用了缓存来提升性能1
2
3
4
5
6
7
8
9
10public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
3.4.2 CglibMethodInvocation.proceed
CglibMethodInvocation是CglibAopProxy中的一个内部类,它继承了`ReflectiveMethodInvocation 并重写了 proceed方法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
36
37
38
39
40
41class CglibAopProxy implements AopProxy, Serializable {
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
public Object proceed() throws Throwable {
return super.proceed();
}
}
````
#### ReflectiveMethodInvocation
`ReflectiveMethodInvocation.proceed` 是CGLIB 动态代理处理目标方法调用 核心逻辑。
它根据`currentInterceptorIndex`来判断是执行Advice 增强逻辑,还是执行目标方法的调用
```java
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 检查当前拦截器索引是否已经到达拦截器链的末尾。如果是,则调用invokeJoinpoint方法,直接执行目标方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 增加当前拦截器索引,并获取下一个拦截器或增强逻辑对象
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
}
ReflectiveMethodInvocation.proceed 的递归调用
ReflectiveMethodInvocation.proceed代码中并没有使用for 循环来执行多个Advice, 而是使用递归调用的方式 实现Advice 增强逻辑 和目标方法的执行
如何理解其中递归调用
- 如果Advice增强 还未全部执行,则取下一个执行Advice, 通过
MethodInterceptor.invoke执行增强逻辑,同时在MethodInterceptor.invoke同样有对ReflectiveMethodInvocation.proceed,继续判断如果是增强,执行同样的操作。 - 如果所有Advice增强 均已被访问过,则调用
invokeJoinpoint()执行目标方法
所以当DynamicAdvisedInterceptor.intercept中执行到new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(),
- 首先来到父类
ReflectiveMethodInvocation.proceed, 通过currentInterceptorIndex判断执行LoggingAdviorLoggingMethodInterceptor.invoke的增强逻辑。 - 进入
LoggingAdviorLoggingMethodInterceptor.invoke后,运行增强逻辑,再次调用ReflectiveMethodInvocation.proceed, 通过currentInterceptorIndex判断执行增强LoggingBeforeAdvice, 程序将LoggingBeforeAdvice包装成了MethodBeforeAdviceIntercept, 调用MethodBeforeAdviceIntercept.invoke - 进入
MethodBeforeAdviceInceptor.invoke后,再次调用ReflectiveMethodInvocation.proceed, 通过currentInterceptorIndex判断执行增强LoggingAfterAdvice,程序将LoggingAfterAdvice包装成了AfterReturningAdviceIntercept, 调用AfterReturningAdviceIntercept.invoke - 进入
MethodBeforeAdviceInceptor.invoke后,再次调用ReflectiveMethodInvocation.proceed, 通过currentInterceptorIndex判断需要执行invokeJoinpoint
执行new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(),来到父类 ReflectiveMethodInvocation.proceed
通过currentInterceptorIndex 判断执行LoggingAdviorLoggingMethodInterceptor.invoke 的增强逻辑。
再次调用 ReflectiveMethodInvocation.proceed,通过currentInterceptorIndex 判断执行增强LoggingBeforeAdvice
再次调用 ReflectiveMethodInvocation.proceed
定义好的before 逻辑执行完成后,再次进入ReflectiveMethodInvocation.proceed, 执行afterAdvice
通过currentInterceptorIndex 判断执行增强LoggingAfterAdvice
再次进入ReflectiveMethodInvocation.proceed,可以看到advice 已经全部执行了,可以去调用invokeJoinpoint,即实际的业务方法了
后面一层层出栈将Advice 的全部执行完成即可。
4. JDK动态代理对象-JdkDynamicAopProxy
如果想要使用JDK 动态代理来实现,需要修改下代码,涉及到的代码修改后如下
1 | public interface UserI { |
XML 文件修改如下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<bean id="userService" class="com.example.codingInAction.service.UserService"/>
<!-- 定义 前置增强-->
<bean id="loggingBeforeAdvice" class="com.example.codingInAction.aop.LoggingBeforeAdvice"/>
<!-- 定义 后置增强 -->
<bean id="loggingAfterAdvice" class="com.example.codingInAction.aop.LoggingAfterAdvice"/>
<!-- 定义 环绕增强 -->
<bean id="loggingAdvisor" class="com.example.codingInAction.aop.LoggingAdvisor"/>
<bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 目标对象 -->
<property name="target" ref="userService"/>
<!-- 指定使用的接口 -->
<property name="proxyInterfaces">
<list>
<value>com.example.codingInAction.service.UserI</value>
</list>
</property>
<!-- 拦截器 -->
<property name="interceptorNames">
<list>
<value>loggingAdvisor</value>
<value>loggingBeforeAdvice</value>
<value>loggingAfterAdvice</value>
</list>
</property>
<!-- 强制使用JDK动态代理 -->
<property name="proxyTargetClass" value="false"/>
</bean>
4.1 getProxy
通过Proxy类,利用反射创建代理对象,整体比较简单,可以参考Java 动态代理中对Proxy 类的介绍,这里不再赘述
1 | final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { |
4.2 实现 InvocationHandler
观察JdkDynamicAopProxy 这个类的定义,可以看到这个类本身就实现了InvocationHandler1
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {}
在java 动态代理中说到,通过Proxy 类获取了一个参数为InvocationHandler 的构造函数创建代理对象,并将自定义的InvocationHandler 传进去
观察JdkDynamicAopProxy 创建代理对象的过程,遵循这一原则,且传进入的参数就是JdkDynamicAopProxy 本身。
4.2 执行目标方法-InvocationHandler.invoke
根据在java 动态代理中学习的源码,对于JDK 动态代理,当执行代理对象的方法时,首先会被自定义InvocationHandler.invoke 方法。 所以这里就是进入到JdkDynamicAopProxy.invoke 方法中
InvocationHandler.invoke 和CGLIB 动态代理中的MethodInterceptor.intercept一样,负责拦截代理对象的方法调用,应用相应的Advice 增强逻辑,并最终调用目标对象的方法。 所以其重点逻辑也是一样的
getInterceptorsAndDynamicInterceptionAdvice获取当前类当前方法上可用的adviceReflectiveMethodInvocation.proceed, 通过ReflectiveMethodInvocation.proceed递归Advice增强逻辑 和目标方法,JdkDynamicAopProxy并没有继承ReflectiveMethodInvocation实现一个新的子类,而是直接使用的ReflectiveMethodInvocation
1 | final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { |
4.3.1 getInterceptorsAndDynamicInterceptionAdvice
和3.4.1 小节中的内容一样
4.3.2 ReflectiveMethodInvocation.proceed
和3.4.1 小节中的逻辑一致, 都是通过ReflectiveMethodInvocation.proceed的递归调用实现增强逻辑和目标方法的执行
5. MethodInterceptor.invoke & MethodInterceptor.intercpt
在前面的内容中, 多次提到MethodInterceptor , MethodInterceptor.invoke和MethodInterceptor.intercpt 这2个方法,要注意区分一下, 这2个MethodInterceptor指的不是同一个,虽然二者的功能类似
5.1 org.springframework.cglib.proxy.MethodInterceptor
org.springframework.cglib.proxy.MethodInterceptor 是 CGLIB(Code Generation Library)库中的接口,
1 | package org.springframework.cglib.proxy; |
在Java 动态代理 CGLIB 动态部分,使用的是这个MethodInterceptor
1 | public class HelloWorldInterceptor implements MethodInterceptor { |
5.2 org.aopalliance.intercept.MethodInterceptor
org.aopalliance.intercept.MethodInterceptor 是 AOP Alliance 规范中的一个接口,Spring AOP 采用了这一规范来提供方法拦截功能。AOP Alliance 是一个标准化的 AOP API 规范,旨在提供统一的 AOP 编程接口。
1 | public interface MethodInterceptor extends Interceptor { |
在Spring AOP 实践, 实现环绕增强时,使用的是这个MethodInterceptor
1 | // 定义一个 环绕增强 |
5.3 区别
org.springframework.cglib.proxy.MethodInterceptor 和 org.aopalliance.intercept.MethodInterceptor 都是强大的方法拦截器接口,允许在方法调用前后添加自定义逻辑。各自有不同的适用场景和实现机制。
- 适用范围:
org.springframework.cglib.proxy.MethodInterceptor适用于基于类的代理,尤其是无接口的类。org.aopalliance.intercept.MethodInterceptor适用于基于接口的代理,广泛用于 Spring AOP 框架中。
- 实现机制:
- CGLIB 基于字节码操作,通过生成目标类的子类实现代理。
- AOP Alliance 基于接口,通过代理接口实现方法拦截。
- 依赖库:
org.springframework.cglib.proxy.MethodInterceptor是 CGLIB 库的一部分,需要引入 CGLIB 依赖。org.aopalliance.intercept.MethodInterceptor是 AOP Alliance 规范的一部分,Spring AOP 默认支持这一规范。
- 方法签名:
- CGLIB 的
MethodInterceptor使用intercept方法,其参数包括目标对象、方法对象、参数数组和方法代理。 - AOP Alliance 的
MethodInterceptor使用invoke方法,其参数是一个封装了方法调用信息的MethodInvocation对象。
- CGLIB 的