Spring 源码阅读:解构 JDK 动态代理 AOP 代理的奥秘
2023-09-03 23:00:38
引言
在软件开发中,我们经常需要在不修改原有代码的情况下为方法添加额外的功能或行为。此时,面向切面编程 (AOP) 便应运而生。AOP 是一种在不修改源代码的情况下为程序添加新功能的技术,它通过在程序执行时动态地拦截和修改方法调用来实现。Spring AOP 是 Spring 框架中强大的 AOP 实现,它支持多种 AOP 代理模式,其中 JDK 动态代理是 Spring AOP 的默认实现方式。
本文将着眼于 Spring AOP 中基于 JDK 动态代理创建的 AOP 代理对象的 invoke 方法,深入分析其工作原理和实现细节。invoke 方法是 AOP 代理对象的核心方法,它是代理方法的入口点,负责处理方法调用并执行 AOP 增强。通过对 invoke 方法的逐行分析,我们将清晰理解 Spring AOP 如何利用 JDK 动态代理机制实现方法增强、拦截和通知。
JDK 动态代理简介
在介绍 invoke 方法之前,我们先简单了解一下 JDK 动态代理。JDK 动态代理是一种在运行时动态创建代理对象的技术。它通过反射机制创建代理类,该代理类继承了目标类并重写了目标类的方法。当调用代理类的方法时,实际上是调用了反射生成的代理方法,代理方法可以实现各种增强操作,例如记录日志、安全检查、性能监控等。
Spring AOP 正是利用了 JDK 动态代理的特性来创建 AOP 代理对象。当 Spring AOP 创建 AOP 代理对象时,它会生成一个代理类,该代理类继承了目标类并重写了目标类的方法。这些重写的方法称为代理方法,它们在调用目标方法之前或之后执行增强操作。
invoke 方法剖析
invoke 方法是 AOP 代理对象的核心方法,它是代理方法的入口点,负责处理方法调用并执行 AOP 增强。invoke 方法的签名如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
其中,
proxy
是 AOP 代理对象本身。method
是被调用的方法。args
是方法参数。
invoke 方法的工作流程大致如下:
- 检查方法是否匹配切入点表达式。
- 如果方法匹配切入点表达式,则执行通知方法。
- 调用目标方法。
- 如果目标方法抛出异常,则执行异常通知方法。
- 返回目标方法的返回值。
下面,我们将逐行分析 invoke 方法的实现,深入了解其工作原理和细节。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation = createMethodInvocation(proxy, method, args);
if (AopUtils.isToStringMethod(method)) {
return invocation.toString();
}
try {
fireBeforeAdvice(invocation);
} catch (Throwable ex) {
return processException(invocation, ex);
}
try {
return doInvokeJoinpoint(invocation);
} catch (Throwable ex) {
return processException(invocation, ex);
} finally {
fireAfterAdvice(invocation);
}
}
1. 创建方法调用对象
MethodInvocation invocation = createMethodInvocation(proxy, method, args);
在 invoke 方法的第一行,我们创建了一个方法调用对象 invocation
。方法调用对象包含了方法调用的所有必要信息,例如代理对象、方法、参数等。
2. 检查方法是否匹配切入点表达式
if (AopUtils.isToStringMethod(method)) {
return invocation.toString();
}
在第二行,我们检查方法是否为 toString
方法。如果方法是 toString
方法,则直接返回方法调用对象的字符串表示。这是因为 toString
方法是 Java 中的一个特殊方法,它用于返回对象的字符串表示。AOP 代理对象不需要对 toString
方法进行增强,因此直接返回字符串表示即可。
3. 执行前置通知
try {
fireBeforeAdvice(invocation);
} catch (Throwable ex) {
return processException(invocation, ex);
}
在第三行,我们执行前置通知。前置通知是在目标方法调用之前执行的通知。Spring AOP 提供了多种前置通知类型,例如 @Before
、@Around
、@AspectJ
等。
如果前置通知抛出异常,则执行异常处理逻辑。异常处理逻辑将在后面的章节中详细介绍。
4. 调用目标方法
try {
return doInvokeJoinpoint(invocation);
} catch (Throwable ex) {
return processException(invocation, ex);
}
在第四行,我们调用目标方法。目标方法是我们要增强的方法。Spring AOP 利用反射机制调用目标方法。
如果目标方法抛出异常,则执行异常处理逻辑。异常处理逻辑将在后面的章节中详细介绍。
5. 执行后置通知
finally {
fireAfterAdvice(invocation);
}
在第五行,我们执行后置通知。后置通知是在目标方法调用之后执行的通知。Spring AOP 提供了多种后置通知类型,例如 @After
、@Around
、@AspectJ
等。
无论目标方法是否抛出异常,后置通知都会执行。
6. 异常处理
在 invoke 方法中,我们使用了异常处理机制来处理目标方法和通知方法抛出的异常。异常处理逻辑如下:
return processException(invocation, ex);
processException
方法负责处理异常。它首先检查异常是否属于 springframework.aop.framework.AopInvocationException
。如果是,则直接抛出异常。否则,它会将异常包装成 springframework.aop.framework.AopInvocationException
,然后抛出。
总结
通过对 invoke 方法的逐行分析,我们清晰理解了 Spring AOP 如何利用 JDK 动态代理机制实现方法增强、拦截和通知。invoke 方法是 AOP 代理对象的核心方法,它负责处理方法调用并执行 AOP 增强。invoke 方法的工作流程是:检查方法是否匹配切入点表达式、执行通知方法、调用目标方法、处理异常、返回目标方法的返回值。
希望本文能够帮助您更深入地理解 Spring AOP 的工作原理和实现细节。如果您有任何问题或建议,欢迎随时提出。