实战CGLib系列文章

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

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

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

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

二、使用CGLib实现

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

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

1、被代理类

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

  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接口。

  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、生成动态代理类

  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。

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

  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操作。

最新文章

  1. javascript中的prototype和constructor
  2. 查看SQL语句在SQL Server上的执行时间
  3. 讲讲Handler+Looper+MessageQueue 关系
  4. 在用busybox制作系统过程中遇到的问题
  5. C#去除字符串的最后一个字符
  6. mac 上的版本控制工具SmartSVN9.0.4(破解版)
  7. fsockopen
  8. Repeater事件OnItemCommand取得行内控件
  9. JavaScript_变量的自动转换和语句
  10. OD: Kernel Exploit - 2 Programming
  11. append, appendTo, after区别(preappend、before与这几个原理相同)
  12. web开发相关
  13. [USACO15JAN]电影移动Moovie Mooving
  14. 如何使用phpstudy本地搭建多站点(每个站点对应不同的端口)
  15. Head First设计模式之备忘录模式
  16. Python面试笔记四
  17. solr 入门
  18. ionic cordova platform add android Cordova failed to install plugin Error: ENOENT: no such file or directory AndroidManifest.xml
  19. CentOS 7.0下安装Python3.6
  20. nodejs高并发大流量的设计实现,控制并发的三种方法

热门文章

  1. java-逻辑处理
  2. git+可视化工具+github/码云
  3. docker安装(4)
  4. 模拟栈&&模拟队列
  5. ubuntu 搭建嵌入式开发环境tftp的方法
  6. iptables简介及常用命令
  7. 牛客练习赛51 B 子串查询 https://ac.nowcoder.com/acm/contest/1083/B
  8. ASP.NET Core 2.0发布/部署到Ubuntu服务器并配置Nginx反向代理
  9. uptime - 告知系统运行了多久时间
  10. UartAssist串口调试工具