JDK动态代理与Cglib动态代理使用详解

news2025/7/14 10:40:07

JDK动态代理与Cglib动态代理使用详解

  • 一、JDK动态代理
    • 准备
    • 使用
  • 二、Cglib动态代理
    • 准备
    • 使用
      • Enhancer.create(Class type, Callback callback)
      • Enhancer.create((Class superclass, Class[] interfaces, Callback callback))
      • Enhancer.create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks)
  • 三、总结对比

一、JDK动态代理

准备

JDK动态代理只能代理接口,所以我们需要先准备一个接口,以及一个接口的实现类

// 需要代理的接口
public interface InvokeInterface {
    void test1(String test,int[] ints);

    String test3(String test);
}

//代理接口的实现类
public class InvokeBean implements InvokeInterface{

    public void test1(String test,int[] ints){
        System.out.println("代理实现方法1 :"+test + JSON.toJSON(ints));
    }

    public String test3(String test){
        System.out.println("代理实现方法1 :"+test);
        return test;
    }
}

有了代理的目标对象了,我们自然还需要一个处理方法,毕竟我们需要实现额外的逻辑呀,不然代理干嘛?对吧,这个处理方法可不能乱写,需要实现InvocationHandler接口,里面有个invoke方法,就是给我们自己写逻辑的地方,我们就可以对方法执行前、后填充自己的逻辑了

注意: 这个类实例化的时候传了一个Object参数,这个就是上面的实现类,为什么要传进来?因为一个接口是可以有多个实现类的,你不传一个具体的实现类,我怎么知道要执行哪个实现类里面的方法呢?

public class DemoInvokeHandler implements InvocationHandler {

    private Object object;

    public DemoInvokeHandler(Object object){
        this.object=object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 所以可以在这里  方法执行前写逻辑
        System.out.println("方法执行前执行");
        
        // 这个就是我们原本的方法执行
        Object invoke=method.invoke(object,args);
        
        // 所以可以在这里  方法执行后写逻辑
        System.out.println("方法执行后执行");
        return invoke;
    }
}

像以上这样呢,整个接口中的方法都会被代理,如果我们只想代理某个方法呢?就需要对方法判断一下如:

这里只是对方法名过滤了,还可以结合注解、参数等过滤

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getName().equals("test1")){
            // 所以可以在这里  方法执行前写逻辑
            System.out.println("方法执行前执行");

            // 这个就是我们原本的方法执行
            Object invoke=method.invoke(object,args);

            // 所以可以在这里  方法执行后写逻辑
            System.out.println("方法执行后执行");
            return invoke;
        }else {
            return method.invoke(object,args);
        }
    }

使用

以上我们的准备工作就完成了,我们只需要在实际使用中,获取代理对象,执行代理对象即可,通过

Proxy.newProxyInstance获取代理对象,有三个传参:

  1. 类加载器
  2. 被代理的接口
  3. 需要做的处理类(也就是实现了InvocationHandler的类)
// 获取代理对象
InvokeInterface invokeBean = (InvokeInterface) Proxy.newProxyInstance(InvokeBean.class.getClassLoader(),
    new Class[]{InvokeInterface.class}, new DemoInvokeHandler(new InvokeBean()));
invokeBean.test1("test1",new int[]{1,2});
String test3 = invokeBean.test3("test3");
System.out.println(test3);

二、Cglib动态代理

准备

这个我们需要先导入依赖包

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>

Cglib和JDK实现起来差不多,但是Cglib代理的是类,所以我们需要先准备个目标类

public class CglibTarget {

    public void test(){
        System.out.println("test 本方法执行");
    }
}

同样的还需要自己的处理方法,这个要实现的接口就不一样。是Callback接口,而该接口有几种:

在这里插入图片描述

我们只看一下MethodInterceptorInvocationHandler两种,其他毕竟用得少:

InvocationHandler:用法和JDK动态代理一样,参考JDK的即可

MethodInterceptor

注意: 是net.sf.cglib.proxy.MethodInterceptor包下的,同时这个处理类实例化的时候就不需要再传参了

public class CglibProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        // 所以可以在这里  方法执行前写逻辑
        System.out.println("方法执行前执行");

        // 这个就是我们原本的方法执行
        Object o1 = methodProxy.invokeSuper(o, objects);

        // 所以可以在这里  方法执行后写逻辑
        System.out.println("方法执行后执行");
        return o1;
    }


}

使用

Cglib的使用同样是需要先生成一个代理对象,一般是靠Enhancer.create() 方法,但该方法有几个重载,我们一个一个介绍

先是最简单也是最常用的

Enhancer.create(Class type, Callback callback)

  • type: 需要代理的类
  • callback:处理方法类
// MethodInterceptor 方式
CglibTarget cglibTarget = (CglibTarget) Enhancer.create(CglibTarget.class, new CglibProxy());
cglibTarget.test();

// InvocationHandler 方式  与JDK一样,不需要类加载器了
Interface cglibTarget = (Interface) Enhancer.create(Interface.class, new CglibProxy(new 实现类));
cglibTarget.test();

结果:
在这里插入图片描述

Enhancer.create((Class superclass, Class[] interfaces, Callback callback))

  • superclass: 需要代理的类
  • interfaces:需要实现的接口
  • callback:处理方法类

这个就比上面那个更厉害了,上面那个只是代理原有类里面的方法,这个可以对代理原有的类帮他实现接口,并实现接口逻辑,这等于一个类凭空多了几个方法出来,怎么用?

上述的目标类不需要改,处理方法需要改一下,然后新建一个接口:

// 我们新建一个接口不需要任何实现类  
public interface TestTarget {
    public void test1();
}

// 修改处理方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    // 这里新增对上面接口里面方法的处理,其他的不需要变
    if(method.getName().equals("test1")){
        // 这里可以实现那个接口方法的逻辑 
        System.out.println("这里写实现那个接口的逻辑方法");
        return "我是那个接口返回的";
    }else {
        // 所以可以在这里  方法执行前写逻辑
        System.out.println("方法执行前执行");

        // 这个就是我们原本的方法执行
        Object o1 = methodProxy.invokeSuper(o, objects);

        // 所以可以在这里  方法执行后写逻辑
        System.out.println("方法执行后执行");
        return o1;
    }
}


调用:

// 先用接口生成器 对我们要实现的接口做一个处理
InterfaceMaker interfaceMaker=new InterfaceMaker();
interfaceMaker.add(TestTarget.class);
Class aClass = interfaceMaker.create();
// 然后我们就可以正常的传参调用了 
CglibTarget o = (CglibTarget)new Enhancer().create(CglibTarget.class, new Class[]{aClass},new CglibProxy());
// 类中方法正常调用
o.test();
// 接口方法调用需要用反射 因为毕竟那接口的方法不存在对象方法里面
Method test1 = o.getClass().getMethod("test1");
test1.invoke(o);

结果:

在这里插入图片描述

Enhancer.create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks)

  • superclass: 需要代理的类
  • interfaces:需要实现的接口
  • filter: 这个就是用来选择处理类的,毕竟处理类有多个了
  • callbacks:处理方法类数组(处理类可以有多个)

为了演示效果,我们新建一个处理类CglibProxyOther,上面的都不需要变

public class CglibProxyOther implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if(method.getName().equals("test1")){
            System.out.println("新建处理类的逻辑方法");
            return "我是那个新建处理类返回的";
        }else {
            // 所以可以在这里  方法执行前写逻辑
            System.out.println("新建处理类——方法执行前执行");

            // 这个就是我们原本的方法执行
            Object o1 = methodProxy.invokeSuper(o, objects);

            // 所以可以在这里  方法执行后写逻辑
            System.out.println("新建处理类——方法执行后执行");
            return o1;
        }
    }
}

然后新增一个过滤选择器filter

实现CallbackFilter接口即可,返回值是处理类数组的下标(我这里用方面名称来选择,实际还可以用其他)

public class CglibFilter implements CallbackFilter {
    @Override
    public int accept(Method method) {
        // test方法用下标为0的处理类
        if(method.getName().equals("test")){
            return 0;
        }
        // 其他方法用下标为1的处理类
        return 1;
    }
}

调用:

InterfaceMaker interfaceMaker=new InterfaceMaker();
interfaceMaker.add(TestTarget.class);
Class aClass = interfaceMaker.create();
CglibTarget o = (CglibTarget)new Enhancer().create(CglibTarget.class, new Class[]{aClass},new CglibFilter(),new Callback[]{new CglibProxy(),new CglibProxyOther()});
o.test();
Method test1 = o.getClass().getMethod("test1");
test1.invoke(o);


结果: 很明显的看到test1方法走了第二个处理类

在这里插入图片描述

至此重载方法全介绍完毕!

三、总结对比

  • 拓展性:要是考虑使用角度Cglib无疑是更好的,因为JDK只能代理接口
  • 原理:JDK代理是利用反射机制生成匿名类,调用也是通过反射来调用
    Cglib是采用字节码技术,通过修改字节码生成子类
  • 效率:JDK创建对象效率较高,但执行较慢,Cglib创建对象效率低,但执行较快
  • 局限性: Cglib需要额外导入第三方包,而Jdk代理不需要,但JDK局限于代理接口

到底用什么相信大家有选择了,如果没特殊需求,就直接JDK得了,有特殊需求不用Cglib,JDK能满足吗?至于效率,这种效率的差距都体现在一定量往上的程度,没到这个量无需考虑太多!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【学习笔记35】JavaScript计算两个指定日期的时间差

一、要求 计算两个指定日期的时间差&#xff08;2023年元旦到来的时间&#xff09; 二、分析 先获取到两个时间距离1970&#xff08;格林尼时间&#xff09;~~~毫秒数计算两个毫秒数的差值 ----> 得到了总毫秒数计算总毫秒数内, 有多少个完整的天 parseInt(总毫秒数 / 一天的…

会话跟踪技术-session和cookie

会话&#xff08;Session&#xff09;跟踪是Web程序中常用的技术&#xff0c;用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。 Cookie通过在客户端记录信息确定用户身份&#xff0c;Session通过在服务器端记录信息确定用户身份。 Cookie对象与HttpSession对象简…

nginx(六十七)http_ssl模块 client与nginx的ssl握手

一 HTTPS握手机制 关注点&#xff1a; SSL/TLS握手的细节与nginx配置指令的关系核心&#xff1a; 讲解客户端(下游)与作为server端的nginx之间的握手最佳实践&#xff1a; 建议在http块中通过include ssl.conf把共工部分抽离处理ssl/tls报错原因&#xff1a;可能是客户端或服…

Flutter高仿微信-第56篇-搜索好友

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; /*** Author : wangning* Email : maoning20080809163.co…

Java---Stream流详解

目录​​​​​​​ 一、Stream流详解 二、Stream流的获取 &#xff08;1&#xff09;单列集合 &#xff08;2&#xff09;双列集合 &#xff08;3&#xff09;数组 &#xff08;4&#xff09;一些零散数据 三、Stream流中常用的API方法 &#xff08;1&#xff09;中间…

含可再生能源的热电联供型微网经济运行优化_粒子群PSO算法_matlab程序

含可再生能源的热电联供型微网经济运行优化matlab程序 参考文献&#xff1a;含可再生能源的热电联供型微网经济运行优化 热电联供系统具有节能! 环保! 经济等特点" 有着良好的发展前景和应用价值# 文中针对由 风电机组! 光伏电池! 燃料电池! 余热锅炉! 燃气锅炉! 蓄电池以…

含电热联合系统的微电网运行优化附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

SpringBoot+Vue项目投稿和稿件处理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

MYSQL中的锁

全局锁 就是对整个数据库进行加锁&#xff0c;加锁之后整个数据库就处于只读状态&#xff0c;后续的DML写语句&#xff0c;DDL语句&#xff0c;以及对更新事务的提交操作都会被阻塞&#xff0c;典型地使用场景就是做整个数据库的逻辑备份&#xff0c;对所有的表进行锁定&#x…

非凡社群管理之如何高效的进行社群管理

一、初始成员的严格筛选 我们建立社群初期&#xff0c;就要严格筛选初始会员&#xff0c;争取让我们找到的第一批种子用户&#xff0c;就是有着共同的连接点。而不是找到一群人之后&#xff0c;再去培养大家的同好。这样不仅吃力不讨好&#xff0c;往往效果也不太高&#xf…

Kafka系列之:实现Kafka Connect集群访问认证

Kafka系列之:实现Kafka Connect集群访问认证 一、Kafka Connect访问控制二、Kafka Connect技术知识三、详细介绍Kafka connect访问认证实现过程四、启动Kafka Connect集群五、测试Kafka Connect集群访问认证一、Kafka Connect访问控制 实现的效果如下所示: 错误的用户名和密…

nginx降权及匹配php

1.nginx降权 1.1 capabilities的介绍与运用 1.2 用普通用户启动nginx 1.3 root用户权限赋予 1.4 查看普通用户的nginx权限 1.5 查看nginx的欢迎网页 2.nginx与php的相互匹配 2.1 安装php及php-fpm包 2.2 检查php-fpm服务运行状态 2.3 php-fpm上的配置 2.4 nginx上的配…

基于matlab的精馏塔作业模拟仿真

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 目录 一、理论基础 二、核心程序 三、测试结果 一、理论基础 原料物性表如下&#xff1a; 表3-1原料物理性质表 组分 质量流率 质量分数 摩尔流率 摩尔分数 分子量 常压沸点 丙烷 472.938 7.567…

SpringBoot SpringBoot 原理篇 1 自动配置 1.9 bean 的加载方式【七】

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇1 自动配置1.9 bean 的加载方式【七】1.9.1 ImportBeanDefinitionRegistrar1 …

mysql 到底是 join性能好,还是in一下更快呢

先总结&#xff1a; 数据量小的时候&#xff0c;用join更划算数据量大的时候&#xff0c;join的成本更高&#xff0c;但相对来说join的速度会更快数据量过大的时候&#xff0c;in的数据量过多&#xff0c;会有无法执行SQL的问题&#xff0c;待解决 事情是这样的&#xff0c;去…

浅谈Spring Cloud Gateway源码

本文不谈Spring Cloud Gateway相关的使用&#xff0c;仅梳理在微服务项目中&#xff0c;在使用Spring Cloud Gateway做为服务网关后&#xff0c;接收到请求后的大体执行流程。 文章目录大致流程图具体流程一、DispatcherHandler二、getHandler1、getHandlerInternal2、lookupRo…

【GlobalMapper精品教程】027:路径剖面和和视线工具的使用

文章目录 一、路径剖面简介二、创建剖面图1. 加载DEM2. 创建剖面图3. 计算填挖方3. 保存剖面图一、路径剖面简介 路径剖面视线工具允许您使用加载的高程数据集沿用户指定的路径获取垂直剖面。 要定义生成3D路径剖面所遵循的路径,只需单击鼠标左键选择路径的点,然后石键单击…

[acwing周赛复盘] 第 60 场周赛20220716

[acwing周赛复盘] 第 60 场周赛20220716 一、本周周赛总结二、 4722. 数列元素1. 题目描述2. 思路分析3. 代码实现三、4723. 队列1. 题目描述2. 思路分析3. 代码实现四、4724. 靓号1. 题目描述2. 思路分析3. 代码实现六、参考链接一、本周周赛总结 第一次打acwing&#xff0c;…

POJ1007:DNA排序

一、Description One measure of unsortedness in a sequence is the number of pairs of entries that are out of order with respect to each other. For instance, in the letter sequence DAABEC’‘, this measure is 5, since D is greater than four letters to its ri…

傻白入门芯片设计,典型的2D/2D+/2.5D/3D封装技术(六)

集成电路终于成为了一级学科&#xff0c;对集成电路领域的投入也日益加大&#xff0c;集成电路属于电子集成技术的一种&#xff0c;那么&#xff0c;现在的电子集成技术发展到了什么程度呢&#xff1f; 先进的电子集成技术可以在不到芝麻粒大小的1平方毫米内集成1亿只以上的晶体…