博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实战CGLib系列之proxy篇(一):方法拦截MethodInterceptor
阅读量:6540 次
发布时间:2019-06-24

本文共 2429 字,大约阅读时间需要 8 分钟。

  hot3.png

实战CGLib系列文章

本篇介绍通过MethodInterceptor和Enhancer实现一个动态代理。

一、首先说一下JDK中的动态代理

JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,不了解的同学请参考我的这篇Blog:Java动态代理详解  

但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。

二、使用CGLib实现

使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

下面,将通过一个实例介绍使用CGLib实现动态代理。

1、被代理类

首先,定义一个类,该类没有实现任何接口,包含两个方法。

Java代码  

  1. public class ConcreteClassNoInterface {  

  2.     public String getConcreteMethodA(String str){  

  3.         System.out.println("ConcreteMethod A ... "+str);  

  4.         return str;  

  5.     }  

  6.     public int getConcreteMethodB(int n){  

  7.         System.out.println("ConcreteMethod B ... "+n);  

  8.         return n+10;  

  9.     }  

  10. }  

2、拦截器

定义一个拦截器。在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。

Java代码  

  1. public class ConcreteClassInterceptor implements MethodInterceptor{  

  2.     public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {  

  3.         System.out.println("Before:"+method);    

  4.         Object object=proxy.invokeSuper(obj, arg);  

  5.         System.out.println("After:"+method);   

  6.         return object;  

  7.     }  

  8. }  

参数:Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。

返回:从代理实例的方法调用返回的值。

其中,proxy.invokeSuper(obj,arg):

调用代理类实例上的proxy方法的父类方法(即实体类ConcreteClassNoInterface中对应的方法)

在这个示例中,只在调用被代理类方法前后各打印了一句话,当然实际编程中可以是其它复杂逻辑。

3、生成动态代理类

Java代码  

  1. Enhancer enhancer=new Enhancer();  

  2. enhancer.setSuperclass(ConcreteClassNoInterface.class);  

  3. enhancer.setCallback(new ConcreteClassInterceptor());  

  4. ConcreteClassNoInterface ccni=(ConcreteClassNoInterface)enhancer.create();  

这里Enhancer类是CGLib中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展,以后会经常看到它。

首先将被代理类ConcreteClassNoInterface设置成父类,然后设置拦截器ConcreteClassInterceptor,最后执行enhancer.create()动态生成一个代理类,并从Object强制转型成父类型ConcreteClassNoInterface。

最后,在代理类上调用方法:

Java代码  

  1. ccni.getConcreteMethodA("shensy");  

  2. ccni.getConcreteMethodB(0);  

查看控制台输出:

控制台代码  

  1. Before :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)  

  2. ConcreteMethod A ... shensy  

  3. After :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)  

  4. Before :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)  

  5. ConcreteMethod B ... 0  

  6. After :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)  

可以看到,拦截器在调用被代理类方法前后都执行了print操作。

转载于:https://my.oschina.net/mn1127/blog/649001

你可能感兴趣的文章
asp.net调用前台js调用后台代码分享
查看>>
Nebula-orchestartor,广域网容器资源协调器
查看>>
mysql 误操作!手贱不可原谅。
查看>>
移动端html页面优化
查看>>
IT价值的三个境界
查看>>
what is the mean of thread safe ?线程安全是什么意思呢?
查看>>
ftp服务器 更加方便的文件传输
查看>>
mysql主从同步 错误测试(1)
查看>>
我的友情链接
查看>>
第二节 虚拟机的安装
查看>>
参加51CTO学院软考培训,我通过啦
查看>>
查看oracle数据库SID
查看>>
判断一个字符串是否为回文字符串
查看>>
1.1 面向对象前部分练习
查看>>
大数据Java-交换变量的 3 种方式
查看>>
使用三台主机部署LNMP
查看>>
如何开展全链路压测&全链路压测核心要素
查看>>
学习php课程的第六天
查看>>
nginx模块开发[转载]
查看>>
持续集成与持续部署宝典Part 1:将构建环境容器化
查看>>