这篇文章主要介绍了Spring5源码之JdkDynamicAopProxy,通过JDK代理使用示例来一步步剖析源码。需要的朋友可以参考一下。
1 、JDK代理使用示例
- 创建业务接口UserService
package com.test.spring5code.jdk.service;
/**
* @Description: 用户服务类
* @Author: Janson
* @Date: 2020/5/1 18:35
**/
public interface UserService {
/**
* 目标方法
*/
abstract void addUser();
}
- 创建业务接口实现类UserServiceImpl
package com.test.spring5code.jdk.service.impl;
import com.test.spring5code.jdk.service.UserService;
import lombok.extern.slf4j.Slf4j;
/**
* @Description: 用户服务实现类
* @Author: Janson
* @Date: 2020/5/1 18:37
**/
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
log.info("======addUser======");
}
}
- 创建自定义的InvocationHandler,用于对接口提供的方法进行增强
package com.test.spring5code.jdk.handler;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Description: 自定义InvocationHandler
* @Author: Janson
* @Date: 2020/5/1 18:39
**/
@Slf4j
public class MyInvocationHandler implements InvocationHandler {
// 目标对象
private Object target;
/**
* 构造方法
*
* @param target
*/
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
/**
* 执行目标对象的方法
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1 在目标对象的方法执行之前简单打印一下
log.info("======before======");
// 2 执行目标对象的方法
Object result = method.invoke(target, args);
// 3 在目标对象的方法执行之后简单打印一下
log.info("======after======");
return result;
}
/**
* 获取目标对象的代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
}
}
- 测试类JDKProxyTest
package com.test.spring5code;
import com.test.spring5code.jdk.handler.MyInvocationHandler;
import com.test.spring5code.jdk.service.UserService;
import com.test.spring5code.jdk.service.impl.UserServiceImpl;
import org.junit.jupiter.api.Test;
/**
* @Description: jdk proxy test
* @Author: Janson
* @Date: 2020/5/1 19:03
**/
public class JDKProxyTest {
@Test
public void testJDKProxy(){
// 1 实例化目标对象
UserService userService = new UserServiceImpl();
// 2 实例化InvocationHandler
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);
// 3 根据目标对象生成代理对象
UserService proxy = (UserService) myInvocationHandler.getProxy();
// 4 调用代理对象的方法
proxy.addUser();
}
}
- 测试类JDKProxyTest输出结果
19:16:36.091 [main] INFO com.test.spring5code.jdk.handler.MyInvocationHandler - ======before======
19:16:36.093 [main] INFO com.test.spring5code.jdk.service.impl.UserServiceImpl - ======addUser======
19:16:36.093 [main] INFO com.test.spring5code.jdk.handler.MyInvocationHandler - ======after======
2 、invoke
JDKProxy的使用关键是创建自定义的InvocationHandler,而InvocationHandler中有invoke方法。在JdkDynamicAopProxy也确实实现了InvocationHandler。下面重点看一下invoke方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 目标本身并不实现equals(Object)方法
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 目标本身并不实现hashCode()方法本身
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// 只有getDecoratedClass()声明->分派到代理配置。
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 如果调用这个方法的 class或接口与参数cls表示的类或者接口相同
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 使用代理配置在ProxyConfig上调用服务。
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理
if (this.advised.exposeProxy) {
// 必要时使调用可用
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//获取此方法的拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 如果没有发现任何拦截器那么直接调用切点方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行拦截器处理
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行拦截器链
retVal = invocation.proceed();
}
// 返回结果
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()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
上面的方法中最主要的工作就是创建了一个拦截器链,并使用了ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐一调用,那么我们继续来探究,在proceed方法中是怎么实现前置增强在目标方法前调用后置增强在目标方法后调用的逻辑呢。
3 、proceed
public Object proceed() throws Throwable {
// 执行完所有增强后执行切点方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个要执行的拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 动态匹配
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 不匹配则不执行拦截器
return proceed();
}
}
else {
// 普通拦截器,直接调用拦截器比如:ExposeInvocationInterceptor,将this昨晚参数传递以保证当前实例中调用链的执行
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
在proceed方法中,或者代码逻辑并没有我们想象得那么复杂,ReflectiveMethodInvocation的主要职责是维护了链接调用的计数器,记录着当前调用链接的位置,以便链可以有序地进行下去,那么在这个方法并没有完美之前深圳的维护各种增强的顺序,而是将工作委托给各个增强器,使各个增强器在内部进行逻辑实现。
如果您觉得有帮助,欢迎点赞收藏哦 ~ ~ 多谢~