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

实战CGLib系列之proxy篇(一):方法拦截MethodInterceptor的更多相关文章

  1. 【WEB API项目实战干货系列】- 导航篇(十足干货分享)

    在今天移动互联网的时代,作为攻城师的我们,谁不想着只写一套API就可以让我们的Web, Android APP, IOS APP, iPad APP, Hybired APP, H5 Web共用共同的 ...

  2. OpenFaaS实战之九:终篇,自制模板(springboot+maven+jdk8)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  3. 深入理解javascript函数系列第三篇——属性和方法

    × 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...

  4. 《手把手教你》系列基础篇(九十七)-java+ selenium自动化测试-框架设计篇-Selenium方法的二次封装和页面基类(详解教程)

    1.简介 上一篇宏哥介绍了如何设计支持不同浏览器测试,宏哥的方法就是通过来切换配置文件设置的浏览器名称的值,来确定启动什么浏览器进行脚本测试.宏哥将这个叫做浏览器引擎类.这个类负责获取浏览器类型和启动 ...

  5. Mysql高手系列 - 第20篇:异常捕获及处理详解(实战经验)

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第20篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...

  6. 【WEB API项目实战干货系列】- API登录与身份验证(三)

    上一篇: [WEB API项目实战干货系列]- 接口文档与在线测试(二) 这篇我们主要来介绍我们如何在API项目中完成API的登录及身份认证. 所以这篇会分为两部分, 登录API, API身份验证. ...

  7. cglib 动态代理基础篇

    cglib 动态代理基础篇 CGlib是什么? CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. 下面我们将通过一个具体的事例来看一下CGli ...

  8. Mysql高手系列 - 第9篇:详解分组查询,mysql分组有大坑!

    这是Mysql系列第9篇. 环境:mysql5.7.25,cmd命令中进行演示. 本篇内容 分组查询语法 聚合函数 单字段分组 多字段分组 分组前筛选数据 分组后筛选数据 where和having的区 ...

  9. Mysql高手系列 - 第22篇:深入理解mysql索引原理,连载中

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第22篇. 背景 使用mys ...

随机推荐

  1. web开发调用百度地图API + AK申请

    web开发调用百度地图API + AK申请 要使用百度地图的API我们首先需要在我们的html页面引入js----`` 如何获取百度地图ak: 1.登陆百度地图开发者平台 2.注册百度开发者账号并登陆 ...

  2. 在Windows的控制台和Linux的终端中显示加载进度

    Windows中 #include <stdio.h> #include <windows.h> int main() { ;//任务完成总量 int i; ; i < ...

  3. java IO 流小结

    java IO 流小结 java流类图结构 流的分类 按方向 输入流 输出流 按类型 字节流 字符流 结论:只要是处理纯文本数据,就优先考虑使用字符流. 除此之外都使用字节流.

  4. Openstack组件部署 — Nova_Install and configure a compute node

    目录 目录 前文列表 Prerequisites 先决条件 Install and configure a compute node Install the packages Edit the etc ...

  5. linux下根据根据进程号查端口、根据端口号查进程号汇总,以及netstat的相关资料(工作中匮乏的知识)

    根据端口查进程: lsof -i:port netstat -nap | grep port 根据进程号查端口: lsof -i|grep pid netstat -nap | grep pid 根据 ...

  6. PAT_A1139#First Contact

    Source: PAT A1139 First Contact (30 分) Description: Unlike in nowadays, the way that boys and girls ...

  7. CSS3 Media Queries模板:max-width和min-width

    CSS3 Media Queries模板 CSS3 Media Queries一般都是使用“max-width”和“min-width”两个属性来检查各种设备的分辨大小与样式表所设条件是否满足,如果满 ...

  8. scala 集合类型

    Iterable 是序列(Seq), 集(Set) 映射(Map)的特质 序列式有序的集合如数组和列表 集合可以通过== 方法确定对每个对象最多包含一个 映射包含了键值映射关系的集合 列表缓存: 使用 ...

  9. D-Ubuntu中修改MySQL的默认数据集(client和server)

    Ubuntu16.04,MySQL5.7 1, sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf 使用vim编辑MySQL的配置文件,不同版本的MySQL配置文件 ...

  10. 基于OpenResty与Consul实现服务网格ServiceMesh

    一.逻辑架构 1.基于OpenResty开发智能代理: 利用其动态可编程特性,动态化配置nginx服务路由: 2.需要向OpenResty添加weibo开源的upsync服务发现模块: 3.基于con ...