实战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. PHP FILTER_SANITIZE_SPECIAL_CHARS 过滤器

    定义和用法 FILTER_SANITIZE_SPECIAL_CHARS 过滤器对特殊字符进行 HTML 转义. 该过滤器用于转义 "<>& 以及 ASCII 值在 32 ...

  2. git stash 保存和恢复进度

    1. stash当前修改 git stash会把所有未提交的修改(包括暂存的和非暂存的)都保存起来,用于后续恢复当前工作目录. 比如下面的中间状态,通过git stash命令推送一个新的储藏,当前的工 ...

  3. AcWing 156. 矩阵 (哈希二维转一维查询)打卡

    给定一个M行N列的01矩阵(只包含数字0或1的矩阵),再执行Q次询问,每次询问给出一个A行B列的01矩阵,求该矩阵是否在原矩阵中出现过. 输入格式 第一行四个整数M,N,A,B. 接下来一个M行N列的 ...

  4. badboy设置参数化

    概述 1.将录制的检查点设置参数化 2.然后回放看结果 ps.设置检查点教程请看上一篇badboy教程 第一:添加变量 第二:将循环次数.请求参数.检查点设置参数化 第三:设置完毕后,点击回放按钮进行 ...

  5. git_全局忽略DS_store

    创建设置文件 vi ~/.gitignore_global 在文件里输入 /*.DS_Store .DS_Store 设置这个文件全局生效 git config --global core.exclu ...

  6. VS2010 下C++使用UTF8编码

    http://www.nubaria.com/en/blog/?p=289 #pragma execution_character_set("utf-8")

  7. 1.4 React 组件生命周期

    1.4.1 组件 React 中组件有自己的生命周期方法,简单理解可以为组件从 出生(实例化) -> 激活 -> 销毁 生命周期 hook.通过这些 hook 方法可以自定义组件的特性. ...

  8. JAVA StringUtils 坑汇总

    1 StringUtils.split() VS String.split(); public static void main(String args[]){            String r ...

  9. 8.1 图像API

    8.1 图像API Routine Description Drawing related functions GUI_AddRect() 调整矩形框的大小 GUI_GetClientRect() R ...

  10. 配置Keepalived单实例实现单IP自动漂移接管

    实验要求 ==> 实现Keepalived高可用对之间的故障切换过程,配置的vrrp实例的VIP为192.168.10.66,可以将其配置在网卡别名上. 实验环境 ==> CentOS 7 ...