本文重点分析 Spring AOP 实践一文中,通过ProxyFactoryBean手动配置动态代理的实现原理。

原理分析将基于以下示例代码。

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
50
51
public class UserService {

public void createUser(String username) {

// 模拟业务处理
System.out.println("Creating user: " + username);
}

public void deleteUser(String username) {

// 模拟业务处理
System.out.println("Deleting user: " + username);
}
}

// 定义一个前置增强
public class LoggingBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before method: " + method.getName());
}
}

// 定义一个后置增强
public class LoggingAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("After method: " + method.getName());
}
}

// 定义一个 环绕增强
public class LoggingMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 方法执行前逻辑
long startTime = System.currentTimeMillis();
System.out.println(invocation.getMethod().getName()+ " 方法开始执行");


// 通过反射执行目标方法
Object result = invocation.proceed();

// 方法执行后逻辑
//System.out.println("After method: " + invocation.getMethod().getName());
long endTime = System.currentTimeMillis();
System.out.println(invocation.getMethod().getName()+ "方法执行时间: " + (endTime - startTime) + "ms");

return result;
}
}
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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 定义业务类的 Bean -->
<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="loggingMethodInterceptor" class="com.example.codingInAction.aop.LoggingMethodInterceptor"/>

<!-- 使用 ProxyFactoryBean 配置代理对象 -->
<bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 目标对象 -->
<property name="target" ref="userService"/>
<!-- 拦截器 -->
<property name="interceptorNames">
<list>
<value>loggingMethodInterceptor</value>
<value>loggingBeforeAdvice</value>
<value>loggingAfterAdvice</value>

</list>
</property>
<!-- 强制使用CGLIB代理 -->
<property name="proxyTargetClass" value="true"/>
</bean>
</beans>

从启动入口开始分析

1
2
3
4
5
6
7
8
9
10
11
12
public class CodingInActionApplication{
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 获取代理对象
UserService userService = (UserService) context.getBean("userServiceProxy");

// 调用方法,观察 AOP 切面的效果
userService.createUser("john");
userService.deleteUser("john");
}
}

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 实例化一文中重点讲过的用于处理FactoryBeangetObjectForBeanInstance 方法, getBean 方法传入的参数name 是&userServiceProxy, 说明经过getObjectForBeanInstance 方法处理后,最终返回了FactoryBean 本身, 在这次debug 过程中,即是ProxyFactoryBean

2.创建动态代理对象-FactoryBean.getObject

Spring IOC 容器启动完成后,就可以从容器中获取需要的bean 了

1
UserService userService = (UserService) context.getBean("userServiceProxy");

由于userServiceProxyFactoryBean, 现在执行getBean("userServiceProxy"), 说明需要获取由它创建的动态代理对象

2.1 getObjectForBeanInstance

进入源码,再次来到getBean 流程,

此时getSingleton,一级缓存中已经有了IOC 容器启动过程的中创建userServiceProxy实例, 直接获取即可。再次进入getObjectForBeanInstance 方法

2.2 FactoryBean.getObject

getObjectForBeanInstance 方法中, 逐层深入源码来到ProxyFactoryBean.getObject 方法。

实现 FactoryBean 接口的类,可以通过重写 getObject 方法来创建并返回实际的对象实例。

分析ProxyFactoryBean.getObject() ,主要代码可以分成2个步骤

  1. initializeAdvisorChain
  2. getSingletonInstance

2.3 initializeAdvisorChain

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
50
51
52
53
54
55
56
57
58
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
// 检查Advisor Chain是否已经初始化
// 如果advisorChainInitialized标志已经为true,表示Advisor Chain已经初始化过了,方法直接返回,不再进行初始化。
if (this.advisorChainInitialized) {
return;
}
// 检查Interceptor名称列表是否为空。如果interceptorNames为空,则跳过初始化。
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}

// Globals can't be last unless we specified a targetSource using the property...
// 检查interceptorNames数组的最后一个元素是否以GLOBAL_SUFFIX结尾。
// 如果是Global类型,并且targetName为null且targetSource为EMPTY_TARGET_SOURCE,
// 则抛出AopConfigException异常,表示在Global Interceptor之后需要一个目标。
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}

// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
// 如果名称以GLOBAL_SUFFIX结尾:
if (name.endsWith(GLOBAL_SUFFIX)) {
// 检查beanFactory是否为ListableBeanFactory类型。如果不是,抛出AopConfigException异常。
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
// 如果是ListableBeanFactory类型, 则将全局Advisor添加到Advisor Chain中。
addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}

else {
// 如果名称不是以GLOBAL_SUFFIX结尾
Object advice;
// 根据名称检查Bean是单例(singleton)还是原型(prototype)。
if (this.singleton || this.beanFactory.isSingleton(name)) {

// 如果是单例或this.singleton为true,则从beanFactory中获取实际的advice实例
// 注意,此时IOC 容器已经启动完成, getBean会从三层缓存中获取实例返回
advice = this.beanFactory.getBean(name);
}
else {
// 如果是原型(prototype),则创建一个对象
advice = new PrototypePlaceholderAdvisor(name);
}
// 将advice添加到Advisor Chain中。
addAdvisorOnChainCreation(advice);
}
}
}

this.advisorChainInitialized = true;
}

该方法的主要逻辑是根据配置的interceptorNames初始化AdvisorChain,确保在执行切面逻辑时,所有的Advisor和Interceptor都已正确配置和初始化。

AdvisorChain 就是一个List数据结构,存储根据interceptorName 获取对应实例

1
advice = this.beanFactory.getBean(name);

对于单例bean来讲,就是从前面启动完成的IOC 容器中,根据name 通过getBean 方法取出对应的实例

2.4 getSingletonInstance

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ProxyFactoryBean extends ProxyCreatorSupport  
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {

private synchronized Object getSingletonInstance() {
this.singletonInstance = getProxy(createAopProxy());

return this.singletonInstance;
}
// 根据确定的动态代理,创建target 的代理对象
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
}

以上代码删除了部分细节,只保留重点逻辑

  1. createAopProxy: 确定动态代理的类型, JDK 动态代理 or CGlib, 判断的逻辑也非常简单,可以简单认为就是有没有实现接口
    1. 实现了接口,用JDK 动态代理
    2. 没有实现接口,用CGlib 动态代理
  2. 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 {

@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.");
}
// 判断目标类是否是接口。如果是接口,使用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
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

class CglibAopProxy implements AopProxy, Serializable {
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}

try {
// 获取目标类的 Class 对象, 并将其设置为代理类的父类,因为cglib代理是通过生成子类的方式实现的
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

Class<?> proxySuperClass = rootClass;
// 检查rootClass的名称是否包含CGLIB的类分隔符 "$$",$$通常用来分隔原始类名和附加的代理类信息
// 如果包含,说明 rootClass 还有它的父类,要把proxySuperClass 设置为这个父类
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
// 获取目标类实现的所有接口,并将这些接口添加到advised对象中。
this.advised.addInterface(additionalInterface);
}
}

// Validate the class, writing log messages as necessary.
// 验证代理超类是否合法
validateClassIfNecessary(proxySuperClass, classLoader);

// Configure CGLIB Enhancer...
// 创建Enhancer实例,用于生成代理类。
Enhancer enhancer = createEnhancer();
// 如果传入了classLoader,则将其设置为Enhancer的类加载器。
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
// 如果类加载器是SmartClassLoader的实例,并且代理类的超类是可重载的,则禁用缓存
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 设置代理类的父类
enhancer.setSuperclass(proxySuperClass);
// 设置代理类实现的接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
// 设置命名策略,确保生成的代理类有合适的名称
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 设置生成策略,使用ClassLoaderAwareGeneratorStrategy来处理类加载器。
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
// 获取用于代理的方法回调, 回调必须实现MethodInterceptor接口
Callback[] callbacks = getCallbacks(rootClass);
// 创建一个与回调数组长度相同的类型数组。将每个回调的类型添加到类型数组中。
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
// 设置回调过滤器,指定哪个回调应该用于哪个方法。
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);

// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
}


class ObjenesisCglibAopProxy extends CglibAopProxy {

@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
// 获取代理类的Class 对象
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;
// 检查是否值得尝试使用Objenesis。
if (objenesis.isWorthTrying()) {
try {
// 如果值得尝试,则尝试使用Objenesis实例化代理对象
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
// 如果proxyInstance仍然是null,则使用常规方式通过默认构造函数实例化代理对象
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
// 获取代理类的构造函数,根据是否有构造参数决定使用哪个构造函数
Constructor<?> ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
// 设置构造函数可访问, private 构造函数是不可访问的
ReflectionUtils.makeAccessible(ctor);
// 使用构造函数实例化代理对象
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}
// 设置回调用
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
}



3.2 ObjenesisCglibAopProxy

从2.4.1-createAopProxy 代码中可以看出,如果是cglib 动态代理,最终返回的是ObjenesisCglibAopProxy,而不是直接返回CglibAopProxy

在Spring AOP框架中,CglibAopProxyObjenesisCglibAopProxy都用于创建CGLIB代理,二者的区别与联系如下

  1. 实例化方式
    • CglibAopProxy: 直接使用CGLIB库的Enhancer类来创建代理类,通常会调用目标类的构造函数。
    • ObjenesisCglibAopProxy: 利用Objenesis库来实例化代理对象,避免了直接调用目标类的构造函数,提供了一种更灵活的实例化方式。
  2. 应用场景
    • CglibAopProxy: 适用于一般的CGLIB代理场景,当目标类的构造函数没有特殊要求时,是Spring AOP的默认选择。
    • ObjenesisCglibAopProxy: 适用于需要在不调用构造函数的情况下创建代理的场景,特别是当目标类的构造函数较为复杂或有特殊限制时,提供了一种更灵活的解决方案。

3.3 getCallbacks-自动实现 MethodInterceptor

Java 动态代理一文, 关于 CGLIB 动态代理,我们手动实现了一个MethodInterceptor, 并将其设置为EnchanerCallback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class HelloWorldInterceptor implements MethodInterceptor {  
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method: " + method.getName());
return result;
}
}

public class CglibDynamicProxyDemo {

public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloWorldImpl.class);
enhancer.setCallback(new HelloWorldInterceptor());

HelloWorld proxy = (HelloWorld) enhancer.create();
proxy.sayHello();
proxy.sayBye();
}
}

3.3.1 Callback

1
2
3
4
5
6
7
8
package org.springframework.cglib.proxy;    
public interface Callback {
}

package org.springframework.cglib.proxy;
public interface MethodInterceptor extends Callback {
Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}

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
50
Callback[] 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信息和代码中的数据是可以一一对应上的

MethodInterceptorCglibAopProxy 有多个实现,均已私有类的形式存在,下面重点分析一下DynamicAdvisedInterceptor,常规的AOP 增强逻辑的织入均是由它实现。

3.4 执行目标方法-DynamicAdvisedInterceptor.intercept

3. 4 方法执行-intercept

经过getProxy获取Cglib 动态代理对象后, 将通过代理对象执行业务逻辑

1
2
userService.createUser("john");  
userService.deleteUser("john");

下面将跟随debug 信息来分析 代理对象方法的执行。
执行userService.createUser("john");

代码会来到CglibAopProxyDynamicAdvisedInterceptor.intercept 方法

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

private final AdvisedSupport advised;

public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}

@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取适用于当前类当前方法的增强,还记得“筛选条件”吗
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 如果拦截器链为空并且方法是public的,直接通过methodProxy调用目标对象的方法。
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 创建一个CglibMethodInvocation对象并调用其proceed方法,执行拦截器链中的所有拦截器逻辑。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

@Override
public boolean equals(@Nullable Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
}

/**
* CGLIB uses this to drive proxy creation.
*/
@Override
public int hashCode() {
return this.advised.hashCode();
}
}

MethodIntercept.intercept, 在本示例中指的是具体实现类DynamicAdvisedInterceptor.intercept 是目标方法执行的拦截入口,拦截后,重点逻辑有2处

  1. getInterceptorsAndDynamicInterceptionAdvice获取当前类当前方法上可用的advice,
  2. CglibMethodInvocation.proceed, 通过ReflectiveMethodInvocation.proceed递归Advice 增强逻辑 和目标方法

3.4.1 getInterceptorsAndDynamicInterceptionAdvice

在增强逻辑和目标方法执行前,,需要先把Spring 容器中所有Advice 进行筛选,获取在当前类当前方法上可用的advice。

关于筛选逻辑,使用的是AdvisorPointcutAdvice

  1. Advisor 是一个复合概念,包括配套的PointcutAdvice
  2. Pointcut 中包含了对类的过滤条件 ClassFilter、方法的过滤条件MethodMatcher
  3. Advice 是符合Pointcut 切点条件的方法上需要执行的增强逻辑。

看图中高亮的66行代码,就是我们在自定义的 LoggingAdvisor、LoggingPointcut重写的方法


最终可以用在UserService.createUser 上的Advice/Interceptor 有3个

  1. 一个自定义的LoggingAdvisor
  2. 2个直接定义的Advice, LoggingBeforeAdviceLoggingAfterAdvice, 它们会被处理成DefaulrPointcutAdvisor, 默认对所有类的所有方法均有效

当执行delete方法是,符合条件的interceptor 只有2个, 符合预期结果

缓存的应用
针对每个方法可用的advice 列表, 这里使用了缓存来提升性能

1
2
3
4
5
6
7
8
9
10
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable 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

CglibMethodInvocationCglibAopProxy中的一个内部类,它继承了`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
41
class CglibAopProxy implements AopProxy, Serializable {
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
@Override
@Nullable
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 增强逻辑 和目标方法的执行

如何理解其中递归调用

  1. 如果Advice增强 还未全部执行,则取下一个执行Advice, 通过MethodInterceptor.invoke执行增强逻辑,同时在MethodInterceptor.invoke 同样有对ReflectiveMethodInvocation.proceed,继续判断如果是增强,执行同样的操作。
  2. 如果所有Advice增强 均已被访问过,则调用invokeJoinpoint()执行目标方法

所以当DynamicAdvisedInterceptor.intercept中执行到new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()

  1. 首先来到父类 ReflectiveMethodInvocation.proceed, 通过currentInterceptorIndex 判断执行LoggingAdviorLoggingMethodInterceptor.invoke 的增强逻辑。
  2. 进入LoggingAdviorLoggingMethodInterceptor.invoke后,运行增强逻辑,再次调用 ReflectiveMethodInvocation.proceed, 通过currentInterceptorIndex 判断执行增强LoggingBeforeAdvice, 程序将LoggingBeforeAdvice包装成了MethodBeforeAdviceIntercept, 调用MethodBeforeAdviceIntercept.invoke
  3. 进入MethodBeforeAdviceInceptor.invoke后,再次调用ReflectiveMethodInvocation.proceed, 通过currentInterceptorIndex 判断执行增强LoggingAfterAdvice,程序将LoggingAfterAdvice包装成了AfterReturningAdviceIntercept, 调用AfterReturningAdviceIntercept.invoke
  4. 进入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
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
public interface UserI {  
void createUser(String username);

void deleteUser(String username);
}


public class UserService implements UserI {
@Override
public void createUser(String username) {

// 模拟业务处理
System.out.println("Creating user: " + username);
}

@Override
public void deleteUser(String username) {
// 模拟业务处理
System.out.println("Deleting user: " + username);

}
}

public class CodingInActionApplication {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

UserI userService = (UserI) context.getBean("userServiceProxy");

// 调用方法,观察 AOP 切面的效果
userService.createUser("john");
userService.deleteUser("john");
}
}

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
2
3
4
5
6
7
8
9
10
11
12
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
}

4.2 实现 InvocationHandler

观察JdkDynamicAopProxy 这个类的定义,可以看到这个类本身就实现了InvocationHandler

1
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 增强逻辑,并最终调用目标对象的方法。 所以其重点逻辑也是一样的

  1. getInterceptorsAndDynamicInterceptionAdvice获取当前类当前方法上可用的advice
  2. ReflectiveMethodInvocation.proceed, 通过ReflectiveMethodInvocation.proceed递归Advice 增强逻辑 和目标方法, JdkDynamicAopProxy并没有继承ReflectiveMethodInvocation实现一个新的子类,而是直接使用的ReflectiveMethodInvocation
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
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

if (chain.isEmpty()) {

Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}

// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {

retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
}

4.3.1 getInterceptorsAndDynamicInterceptionAdvice

和3.4.1 小节中的内容一样

4.3.2 ReflectiveMethodInvocation.proceed

和3.4.1 小节中的逻辑一致, 都是通过ReflectiveMethodInvocation.proceed的递归调用实现增强逻辑和目标方法的执行

5. MethodInterceptor.invoke & MethodInterceptor.intercpt

在前面的内容中, 多次提到MethodInterceptorMethodInterceptor.invokeMethodInterceptor.intercpt 这2个方法,要注意区分一下, 这2个MethodInterceptor指的不是同一个,虽然二者的功能类似

5.1 org.springframework.cglib.proxy.MethodInterceptor

org.springframework.cglib.proxy.MethodInterceptor 是 CGLIB(Code Generation Library)库中的接口,

1
2
3
4
package org.springframework.cglib.proxy;
public interface MethodInterceptor {
Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}

Java 动态代理 CGLIB 动态部分,使用的是这个MethodInterceptor

1
2
3
4
5
6
7
8
9
public class HelloWorldInterceptor implements MethodInterceptor {  
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method: " + method.getName());
return result;
}
}

5.2 org.aopalliance.intercept.MethodInterceptor

org.aopalliance.intercept.MethodInterceptor 是 AOP Alliance 规范中的一个接口,Spring AOP 采用了这一规范来提供方法拦截功能。AOP Alliance 是一个标准化的 AOP API 规范,旨在提供统一的 AOP 编程接口。

1
2
3
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}

Spring AOP 实践, 实现环绕增强时,使用的是这个MethodInterceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 定义一个 环绕增强
public class LoggingMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 方法执行前逻辑
long startTime = System.currentTimeMillis();
System.out.println(invocation.getMethod().getName()+ " 方法开始执行");

// 通过反射执行目标方法
Object result = invocation.proceed();

// 方法执行后逻辑
//System.out.println("After method: " + invocation.getMethod().getName());
long endTime = System.currentTimeMillis();
System.out.println(invocation.getMethod().getName()+ "方法执行时间: " + (endTime - startTime) + "ms");

return result;
}
}

5.3 区别

org.springframework.cglib.proxy.MethodInterceptororg.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 对象。