发布于2021-05-29 19:45 阅读(682) 评论(0) 点赞(16) 收藏(3)
看了Spring AOP JDK动态代理部分的源码,想尝试借鉴Spring的思想,实现一个“增强版”的JDK动态代理。
本博文以及相关代码仅作为练习使用,欢迎指正和交流探讨。
UserService userService = new UserServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);
Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),invocationHandler);
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(MyInvocationHandler myInvocationHandler) {
this.myInvocationHandler = myInvocationHandler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强代码
...
return method.invoke(target,args);
}
}
以上是大家很熟悉的创建JDK代理的代码。
我们的增强的代码全都在InvocationHandler
的invoke
方法中。
想象一下,我们想要对某个类进行代理,使代理类在各个不同的方面进行增强,那么invoke
方法将会变得很重。
分析了原生JDK代理的现状之后我们目标自然也就出来了:根据单一职责原则,希望将不同类型的增强逻辑定义在不同的类中,然后让不同增强类的增强逻辑一起作用在目标类上,达到一种层层增强的效果。
为了达成目标里提到的“单一职责原则”,需要先定义一个抽象类,这个类定义了增强逻辑,我们称它为“方法拦截器”:
/**
* @author xujian
* 2021-05-26 10:11
**/
public abstract class MethodInterceptor {
/**
* 执行增强
* @param chain
* @param joinPointInfo
* @return
* @throws Exception
*/
public final void proceed(InterceptorChain chain, JoinPointInfo joinPointInfo) throws Exception {
proceed(joinPointInfo);
chain.proceed(joinPointInfo);
}
/**
* 用户自定义增强逻辑
* @param joinPointInfo
*/
abstract void proceed(JoinPointInfo joinPointInfo);
/**
* 获取连接点类型
* @return
*/
abstract JoinPointEnum getJoinPoint();
/**
* 获取顺序编号,可以重写该方法修改默认排序
* @return
*/
public int getOrder() {return 1;}
}
proceed
,这是给使用者自己去实现的方法,这个方法应当是要增强的逻辑。final
方法proceed
,这个方法在“拦截器链”中被调用,是责任链设计模式的实现。getJoinPoint
,该方法是用来获取当前的“方法拦截器”的增强逻辑作用的时机,如:目标方法执行前增强,目标方法返回后执行。getOrder
,该方法返回一个序号,序号小越先执行增强逻辑。于此同时需要定义一个连接所有“方法拦截器”的链条,称它为“拦截器链”:
/**
* 拦截器链
* @author xujian
* 2021-05-26 10:09
**/
public class InterceptorChain {
/**
* 方法执行前拦截器列表
*/
private List<MethodInterceptor> beforeInterceptors;
/**
* 方法正常返回后拦截器列表
*/
private List<MethodInterceptor> afterReturnInterceptors;
private int currentBeforeInterceptorIndex = -1;
private int currentAfterReturnInterceptorIndex = -1;
/**
* 是否已经执行过目标方法
*/
private boolean isTargetMethodExecuted;
public InterceptorChain(List<MethodInterceptor> interceptors) {
//根据增强时机(连接点)分组
Map<String, List<MethodInterceptor>> interceptorMap =
interceptors.stream().collect(groupingBy(m -> m.getJoinPoint().getName()));
//方法执行前增强的拦截器
beforeInterceptors = interceptorMap.get(JoinPointEnum.BEFORE.getName());
//按照order排序
beforeInterceptors.sort(Comparator.comparingInt(MethodInterceptor::getOrder));
//方法返回后增强的拦截器
afterReturnInterceptors = interceptorMap.get(JoinPointEnum.AFTER_RETURN.getName());
//按照order排序
afterReturnInterceptors.sort(Comparator.comparingInt(MethodInterceptor::getOrder));
}
/**
* 执行方法
* @param joinPointInfo
* @return
* @throws Exception
*/
public Object proceed(JoinPointInfo joinPointInfo) throws Exception {
//方法执行前增强
before(joinPointInfo);
if (!isTargetMethodExecuted) {
//执行目标方法
Object o = joinPointInfo.getMethod().invoke(joinPointInfo.getTarget(),joinPointInfo.getArgs());
isTargetMethodExecuted = true;
joinPointInfo.setReturnValue(o);
}
//方法返回后增强
afterReturn(joinPointInfo);
return joinPointInfo.getReturnValue();
}
public void before(JoinPointInfo joinPointInfo) throws Exception {
if (currentBeforeInterceptorIndex == beforeInterceptors.size() - 1) {
return;
}
MethodInterceptor methodInterceptor = beforeInterceptors.get(++currentBeforeInterceptorIndex);
methodInterceptor.proceed(this,joinPointInfo);
}
public void afterReturn(JoinPointInfo joinPointInfo) throws Exception {
if (currentAfterReturnInterceptorIndex == afterReturnInterceptors.size() - 1) {
return;
}
MethodInterceptor methodInterceptor = afterReturnInterceptors.get(++currentAfterReturnInterceptorIndex);
methodInterceptor.proceed(this,joinPointInfo);
}
}
proceed
里面完成对目标方法的“前置”、“后置”增强。brfore
和afterReturn
分别是“前置”和“后置”增强的具体实现,里面会调用“方法拦截器”的proceed
方法,这也是实现责任链设计模式的一部分。因为我们是对原生JDK代理的增强,所以还是需要依赖原生的JDK代理功能:
/**
* @author xujian
* 2021-05-26 10:58
**/
public class EnhanceInvocationHandler implements InvocationHandler {
//目标对象
private Object target;
//拦截器链
private InterceptorChain chain;
public EnhanceInvocationHandler(Object target, List<MethodInterceptor> interceptors) {
this.target = target;
this.chain = new InterceptorChain(interceptors);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
JoinPointInfo joinPointInfo = JoinPointInfo.Builder.newBuilder()
.method(method).target(target).proxy(proxy).args(args)
.build();
//执行方法增强
return chain.proceed(joinPointInfo);
}
}
InvocationHandler
实现,不需要使用者再去实现InvocationHandler
。为了让使用者用类似使用原生的JDK代理的方式使用增强的JDK代理,需要定义一个代理生成类:
/**
* 增强的jdk代理
* @author xujian
* 2021-05-26 10:06
**/
public class EnhanceProxy {
/**
* 获取代理类
* @param loader
* @param interfaces
* @param h
* @return
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
EnhanceInvocationHandler h) {
return Proxy.newProxyInstance(loader,interfaces,h);
}
}
newProxyInstance
方法,这个和原生的JDK代理类Proxy.newProxyInstance(...)
很类似,但是它最后一个参数只接受EnhanceInvocationHandler
类型,这个不同于原生的JDK代理。因为EnhanceInvocationHandler
是作为内部唯一默认且固定的实现而存在。定义好了核心组件之后,测试一下。
该测试仅验证是否能够达到预期的效果。
预期效果
有一个打印方法print
,想要在该方法执行之前做两层增强,以后在该方法返回后执行两层增强。
首先,需要继承MethodInterceptor
来编写增强逻辑。
BeforeMethodInterceptor
/**
* @author xujian
* 2021-05-26 11:35
**/
public class BeforeMethodInterceptor extends MethodInterceptor {
/**
* 用户自定义增强逻辑
*
* @param joinPointInfo
*/
@Override
void proceed(JoinPointInfo joinPointInfo) {
System.out.println("----before");
}
/**
* 获取连接点类型
*
* @return
*/
@Override
JoinPointEnum getJoinPoint() {
return JoinPointEnum.BEFORE;
}
/**
* 获取顺序编号,可以重写该方法修改默认排序
*
* @return
*/
@Override
public int getOrder() {
return 2;
}
}
BeforeBeforeMethodInterceptor
/**
* @author xujian
* 2021-05-26 11:35
**/
public class BeforeBeforeMethodInterceptor extends MethodInterceptor {
/**
* 用户自定义增强逻辑
*
* @param joinPointInfo
*/
@Override
void proceed(JoinPointInfo joinPointInfo) {
System.out.println("----beforebefore");
}
/**
* 获取连接点类型
*
* @return
*/
@Override
JoinPointEnum getJoinPoint() {
return JoinPointEnum.BEFORE;
}
}
AfterReturnMethodInterceptor
/**
* @author xujian
* 2021-05-26 11:35
**/
public class AfterReturnMethodInterceptor extends MethodInterceptor {
/**
* 用户自定义增强逻辑
*
* @param joinPointInfo
*/
@Override
void proceed(JoinPointInfo joinPointInfo) {
System.out.println("----after");
}
/**
* 获取连接点类型
*
* @return
*/
@Override
JoinPointEnum getJoinPoint() {
return JoinPointEnum.AFTER_RETURN;
}
}
AfterAfterReturnMethodInterceptor
/**
* @author xujian
* 2021-05-26 11:35
**/
public class AfterAfterReturnMethodInterceptor extends MethodInterceptor {
/**
* 用户自定义增强逻辑
*
* @param joinPointInfo
*/
@Override
void proceed(JoinPointInfo joinPointInfo) {
System.out.println("----afterafter");
joinPointInfo.setReturnValue("我是"+this.getClass().getSimpleName()+"拦截器修改以后的返回值");
}
/**
* 获取连接点类型
*
* @return
*/
@Override
JoinPointEnum getJoinPoint() {
return JoinPointEnum.AFTER_RETURN;
}
}
目标类:
/**
* @author xujian
* 2021-05-26 11:32
**/
public class UserServiceImpl implements UserService {
@Override
public String print() {
System.out.println("----UserService的打印方法");
return "我是返回值";
}
}
测试类:
@Test
public void test01() {
UserService userService = new UserServiceImpl();
//为目标类添加方法拦截器即要增强的逻辑,请注意添加顺序
List<MethodInterceptor> interceptors = new ArrayList<>();
interceptors.add(new BeforeMethodInterceptor());
interceptors.add(new BeforeBeforeMethodInterceptor());
interceptors.add(new AfterReturnMethodInterceptor());
interceptors.add(new AfterAfterReturnMethodInterceptor());
EnhanceInvocationHandler enhanceInvocationHandler = new EnhanceInvocationHandler(userService,interceptors);
//生成代理对象
UserService userService1 = (UserService) EnhanceProxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),enhanceInvocationHandler);
System.out.println(userService1.print());
}
注意上面“方法拦截器”的添加顺序。
执行结果
----beforebefore
----before
----UserService的打印方法
----after
----afterafter
方法返回结果:我是AfterAfterReturnMethodInterceptor拦截器修改以后的返回值
BeforeMethodInterceptor
重写了getOrder
方法,返回了2,从而调整了顺序。相关代码请参考:https://gitee.com/xujian01/blogcode/tree/master/src/main/java/enhancejdkproxy
原文链接:https://blog.csdn.net/qq_18515155/article/details/117334651
作者:飞人出击
链接:http://www.javaheidong.com/blog/article/207215/1de0789a383ceac44249/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!