CGLib动态代理和JDK动态代理Demo、ASM技术尝鲜

news2024/10/6 4:39:06

本文主要介绍CGLib和JDK动态代理的使用,不对源码进行深入分析。代码可直接复制使用。

类型

机制

回调方式

适用场景

效率

JDK动态代理

委托机制。代理类和目标类都实现了同样的接口。InvocationHandler持有目标类。代理类委托InvocationHandler去调用目标类原始方法

反射

目标类实现接口

反射调用稍慢。

CGLIB动态代理

继承机制。代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑(底层使用到ASM技术,操作字节码生成代理类)

通过FastClass方法索引调用

非final类,非final方法

第一次调用因为要生成多个Class对象较]DK慢,但是调用时方法索引较反射方式快

代码框架:

类UserInterface

package com.cocoa.dao;

public interface UserInterface {
    public void test();
}

类UserService

package com.cocoa.dao;

public class UserService implements UserInterface{

    @Override
    public void test() {
        System.out.println("UserService test() -- print");
    }
}

类CGLIBDemo

method.invoke()使用的还是反射机制;但是methodProxy.invoke使用的不是反射,而是FastClass机制,通过建立代理类的索引,快速执行代理的方法。(所以比JDK快)

MethodIntercept的入参:

o:目标对象的实例(被代理的对象);

method:被代理的方法;

objects:方法调用时的入参;

methodProxy:用于调用原始方法的代理。

package com.cocoa.enhancer;

import com.cocoa.dao.UserService;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLIBDemo {
    public static void Main(String[] args) {
        // 动态代理生成的字节码存储到本地
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "com.cocoa.enhancer");
        final UserService target = new UserService();
        // 增强器
        Enhancer enhancer = new Enhancer();
        // enhancer.setUseCache(false);// 使用缓存
        // 设置代理的类
        enhancer.setSuperclass(UserService.class);
        // 设置代理逻辑
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                if (method.getName().equals("test")){

                    System.out.println("before...");
                    method.invoke(target, objects);
                    System.out.println("after...");
                }
                return null;
            }
        });
        // 使用代理类
        UserService userService = (UserService) enhancer.create();// create会将第一次产生的代理类缓存下来
        userService.test();
    }
}

要避免使用method.invoke(),应该使用methodProxy。

类CGLIBDemo1

使用methodProxy.invoke执行方法(通过FastCLass索引机制)

methodProxy.invoke(target, objects);// test() 正常运行,直接执行代理方法

methodProxy.invoke(o, objects);// o 表示代理对象,这样会导致死循环

methodProxy.invokeSuper(target, objects);// CGLIB$test$4() 因为target中没有代理对象的方法

methodProxy.invokeSuper(o, objects);// CGLIB$test$4() 执行代理对象o中的test方法 正常运行

package com.cocoa.enhancer;

import com.cocoa.dao.UserService;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * MethodProxy的使用
 */
public class CGLIBDemo1 {
    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "com.cocoa.enhancer");

        final UserService target = new UserService();
        // 增强器
        Enhancer enhancer = new Enhancer();
        // enhancer.setUseCache(false);// 使用缓存
        // 设置代理的类
        enhancer.setSuperclass(UserService.class);
        // 设置代理逻辑
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            // o代理对象 objects入参 method被代理的方法 methodProxy代理的方法
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                if (method.getName().equals("test")){
                    System.out.println("before...");
                    // MethodProxy 表示方法代理,代理了两个方法 test()
//                    methodProxy.invoke(target, objects);// test() 可用
//                    methodProxy.invoke(o, objects);// o 表示代理对象,这样会导致死循环
//                    methodProxy.invokeSuper(target, objects);// CGLIB$test$4() 因为target中没有代理对象的方法
                    methodProxy.invokeSuper(o, objects);// CGLIB$test$4() 执行代理对象o中的test方法 可用

                    System.out.println("after...");
                }
                return null;
            }
        });
        // 使用代理类
        UserService userService = (UserService) enhancer.create();// create会将第一次产生的代理类缓存下来
        userService.test();
    }
}

类mainInterface

package com.cocoa.enhancer;

import com.cocoa.dao.UserInterface;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * CGLIB 可以代理接口
 */
public class mainInterface {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        // 设置代理的接口
        enhancer.setSuperclass(UserInterface.class);
        // 设置代理逻辑
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("切面逻辑...");
                return null;
            }
        });
        // 使用代理类
        UserInterface userInterface = (UserInterface) enhancer.create();
        userInterface.test();
    }
}

类JDKDemo

使用proxy.newProxyInstance方法直接构造代理类,入参有:

1)真实对象的类加载器;

2)真实对象实现的接口;

3)代理类需要实现InvocationHandler接口,重写Invoke方法。

invoke方法的入参:

参数1:用Proxy.newProxyInstance方法产生的真实对象,注意,参数1并不显式地出现在方法体内;

参数2:要调用的目标方法;

参数3:目标方法中的参数,一般是  Object[ ]  args。

package com.cocoa.jdkProxy;

import com.cocoa.dao.UserInterface;
import com.cocoa.dao.UserService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKDemo {
    public static void main(String[] args) {
        // Proxy.newproxyInstance
        // 类加载器、代理的接口、new InvocationHandler
        UserService target = new UserService();
        UserInterface userInterface = (UserInterface) Proxy.newProxyInstance(
                JDKDemo.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("test");
                method.invoke(target, args);
                return null;
            }
        });
        userInterface.test();
    }
}

ASM技术尝鲜

通过ASM字节码技术,可以生成一个类。执行下面的代码,就可以生成下图中的类。

package com.cocoa.asmDemo;

import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * ASM 尝鲜使用
 */
public class ASMDemo {
    public static void main(String[] args) throws IOException {
        ClassWriter classWriter = new ClassWriter(0);
        // 通过visit 方法确定类的头部信息
        classWriter.visit(Opcodes.V1_8,// java版本
                Opcodes.ACC_PUBLIC,// 类修饰符
                "Person", // 类的全限定名
                null, "java/lang/Object", null );

        // 创建构造函数
        MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.AALOAD, 0);// 字节码指令
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1,1);
        mv.visitEnd();

        // 定义test方法
        MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "test", "()V", null, null);
        methodVisitor.visitCode();
        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        methodVisitor.visitLdcInsn("hello zhouyu");
        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream","println","(Ljava/lang/string;)V");
        methodVisitor.visitInsn(Opcodes.RETURN);
        methodVisitor.visitMaxs(2,2);
        methodVisitor.visitEnd();
        classWriter.visitEnd();

        // 使classWriter类已经完成
        // 将classWriter转换成字节数组写到文件里面大
        byte[] data =classWriter.toByteArray();
        File file = new File( "E:\\java_shicao\\DynamicProxyDemo\\src\\main\\java\\People.class");
        FileOutputStream fout = new FileOutputStream(file);
        fout.write(data);
        fout.close();

    }
}

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

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

相关文章

令牌主动失效机制范例(利用redis)注释分析

介绍该机制 令牌生成 在需要限流的场景中&#xff0c;系统会根据一定的速率生成令牌&#xff0c;存储在 Redis 中。可以设定每秒生成的令牌数量。 令牌获取 当用户请求时&#xff0c;系统会从 Redis 中获取令牌。可以使用原子性操作&#xff08;如 DECR&#xff09;来确保令牌…

SHAP分析

SHAP分析&#xff08;SHapley Additive exPlanations&#xff09;是一种基于博弈论的解释机器学习模型输出的方法。它提供了一种统一的方式来解释模型的预测结果&#xff0c;量化每个特征对模型预测的贡献&#xff0c;能够为复杂的机器学习模型&#xff08;如随机森林、梯度提升…

C语言基础(8)之操作符(2)(详解)

目录 1. 操作符汇总表 2. 关系操作符 3. 条件操作符 4. 逗号表达式 5. 下标引用、函数调用和结构成员 5.1 下标引用 5.2 函数调用操作符 5.3 结构成员 6. 操作符的属性 6.1 操作符的优先级 大家好呀&#xff01;上篇文章中我们详细讲解了操作符的前半部分&#xff0c…

【成长day】SuperPointSuperGlue(01): Superpoint论文算法学习与对应源码解析

两年前自己在实习公司做过superpoint相关的工作&#xff0c;当时是负责利用superpoint代替slam前端的特征点部分&#xff0c;来达到把特征点相关的处理放到推理计算平台上减轻CPU压力并且精度无损的目的&#xff0c;最终也是成功完成了这部分工作。但是当时没有留下任何的记录&…

YOLOv8 基于MGD的知识蒸馏

YOLOv8 基于MGD的知识蒸馏 接着上一篇我们介绍了YOLOv8的剪枝方案和代码&#xff0c;本篇文章将剪枝后的模型作为学生模型&#xff0c;剪枝前的模型作为教师模型对剪枝模型进行蒸馏&#xff0c;从而进一步提到轻量模型的性能。 Channel-wise Distillation (CWD) 问题和方法 …

IDM下载器如何下载网盘文件 IDM下载器支持哪些网盘

不用开通会员&#xff0c;也能高速下载网盘文件。使用IDM下载加速器&#xff0c;直接从服务器高速下载文件&#xff0c;轻松突破网盘限速。掌握IDM下载网盘文件的技巧&#xff0c;不仅可以节省会员费用&#xff0c;还可以大幅提高下载效率。有关IDM下载器如何下载网盘文件&…

【Linux:线程控制】

目录 线程的创建与等待&#xff1a; ​编辑 代码中tid是什么&#xff1f; 如何看待线程函数传参&#xff1f; ​编辑 ​编辑创建多线程&#xff1a;​编辑 终止多线程&#xff1a; 线程分离&#xff1a; 线程的创建与等待&#xff1a; void *threadrun(void *args) {int …

QT 中如何保存matlab 能打开的.mat数据矩阵!

Windows 上安装并使用 MATIO 库来保存 MATLAB 格式的 .mat 文件&#xff0c;需要进行以下步骤&#xff1a; 1. 下载并安装 CMake MATIO 使用 CMake 构建项目&#xff0c;因此你需要先安装 CMake。 前往 CMake 官网下载适用于 Windows 的安装程序并安装。 2. 下载 MATIO 库源…

Unity基础-矩阵-坐标转换结果的个人理解+数学公式说明

想做一些渲染效果做到头大&#xff0c;根本很多空白&#xff0c;完全无法实现&#xff0c;只能先暂停一下&#xff0c;重新学习矩阵 目录 Unity基础-数学矩阵 1.我们利用最简单的“转换矩阵”&#xff0c; 2.然后&#xff0c;视图坐标又是如何 3.最后就是剪裁坐标 3.1 - 其…

硬件设计-利用环路设计优化PLL的输出性能

目录 前言 问题描述 问题分析步骤 杂散源头排查 245.76M 参考相噪&#xff1a; 30.72M VCXO的相噪性能测试如下: 解决方案 前言 LMK04832是TI 新发布的低抖动双环去抖模拟时钟&#xff0c; 其最高输出频率可以到达3250MHz&#xff0c; 输出抖动极低&#xff0c;3200MHz…

MySQL 中的数据库锁和表锁

在 MySQL 数据库中&#xff0c;为了保证数据的一致性和完整性&#xff0c;会使用各种类型的锁。其中&#xff0c;数据库锁和表锁是比较常见的两种锁类型。 一、数据库锁和表锁的概念 &#xff08;一&#xff09;数据库锁 数据库锁是对整个数据库进行锁定&#xff0c;限制对数…

尝试从 http://pypi.doubanio.com/simple 这个索引源安装 webdriver 时出现了问题

问题如下&#xff1a; WARNING: The repository located at pypi.doubanio.com is not a trusted or secure host and is being ignored. If this repository is available via HTTPS we recommend you use HTTPS instead, otherwise you may silence this warning and allow …

ElasticSearch备考 -- 异步检索

一、题目 通过异步方式查询earthquakes索引下Magnitude大于5的数据 二、思考 正常的查询大家可能会用的多一点&#xff0c;这种异步查询为了可以数据量量比较大的查询在后台执行&#xff0c;不用同步等待结果&#xff0c;待执行完成在获取结果。 三、解题 Step 1、准备基础数…

【深度强化学习基础】(一)基本概念

【深度强化学习基础】&#xff08;一&#xff09;基本概念 一、概率论基础知识二、强化学习领域术语三、强化学习中两个随机性的来源&#xff1a;四、rewards以及returns五、Value Functions1.Action-Value Function Q π ( s , a ) Q_\pi(s,a) Qπ​(s,a)1.State-Value Funct…

Yolov8改进WIoU,SIoU,EIoU,α-IoU

1,IOU原理部分 IoU(Intersection over Union)是一种在计算机视觉领域常用的性能评估指标,尤其在目标检测和图像分割任务中。它通过计算预测边界框(预测框)与真实边界框(真实框)之间的交集面积与并集面积之比来衡量预测的准确性。IoU的值越接近1,表示预测框与真实框的重…

Error while loading conda entry point: conda-libmamba-solver

问题 解决方法 conda install --solverclassic conda-forge::conda-libmamba-solver conda-forge::libmamba conda-forge::libmambapy conda-forge::libarchive

C0015.Clion中开发C++时,连接Mysql数据库方法

安装mysql数据库 CMakeLists.txt中配置mysql数据库 # 先指定mysql数据库的安装位置 include_directories("C:/Program Files/MySQL/MySQL Server 8.0/include") link_directories("C:/Program Files/MySQL/MySQL Server 8.0/lib") link_libraries(libmysq…

Python | 使用Seaborn绘制KDE核密度估计曲线

核密度估计&#xff08;KDE&#xff09;图&#xff0c;一种可视化技术&#xff0c;提供连续变量概率密度的详细视图。在本文中&#xff0c;我们将使用Iris Dataset和KDE Plot来可视化数据集。 什么是KDE图&#xff1f; KDE图&#xff0c;全称核密度估计图(Kernel Density Est…

智慧农业案例 (二)- 智能化灌溉系统

橙蜂智能公司致力于提供先进的人工智能和物联网解决方案&#xff0c;帮助企业优化运营并实现技术潜能。公司主要服务包括AI数字人、AI翻译、领域知识库、大模型服务等。其核心价值观为创新、客户至上、质量、合作和可持续发展。 橙蜂智农的智慧农业产品涵盖了多方面的功能&…

回归预测|基于哈里斯鹰优化最小二乘支持向量机的数据回归预测Matlab程序HHO-LSSVM 多特征输入单输出含基础程序

回归预测|基于哈里斯鹰优化最小二乘支持向量机的数据回归预测Matlab程序HHO-LSSVM 多特征输入单输出含基础程序 文章目录 一、基本原理一、基本原理二、HHO-LSSVM的流程三、优缺点四、应用场景 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 HHO-LSSVM回归预测结…