动态代理的两种方式以及区别

2023-11-14

JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。

强制使用CGlib

<!-- proxy-target-class="false"默认使用JDK动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<aop-config proxy-target-class="true">
<!-- 切面详细配置 -->
</aop-config>

具体代码示例:

/**
 * 目标接口类
 */
public interface UserManager {    
    public void addUser(String id, String password);    
    public void delUser(String id);    
}
/**
 * 接口实现类
 */
public class UserManagerImpl implements UserManager {    
    
    @Override
    public void addUser(String id, String password) {    
        System.out.println("调用了UserManagerImpl.addUser()方法!");
    }    
    
    @Override
    public void delUser(String id) {    
        System.out.println("调用了UserManagerImpl.delUser()方法!");
    }    
}
/**
 * JDK动态代理类
 */
public class JDKProxy implements InvocationHandler {    
    
    // 需要代理的目标对象
    private Object targetObject;    
    
    public Object newProxy(Object targetObject) {
        // 将目标对象传入进行代理    
        this.targetObject = targetObject;
        // 返回代理对象 
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }    
    
    // invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 进行逻辑处理的函数
        checkPopedom();
        Object ret = null;
        // 调用invoke方法
        ret = method.invoke(targetObject, args);
        return ret;
    }    
    
    private void checkPopedom() {
        // 模拟检查权限   
        System.out.println("检查权限:checkPopedom()!");    
    }    
} 
/**
 * CGlib动态代理类
 */
 public class CGLibProxy implements MethodInterceptor {    
    
    // CGlib需要代理的目标对象
    private Object targetObject;
    
    public Object createProxyObject(Object obj) {
        this.targetObject = obj;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(this);
        Object proxyObj = enhancer.create();
        return proxyObj;
    }
    
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object obj = null;
        // 过滤方法
        if ("addUser".equals(method.getName())) {
            // 检查权限
            checkPopedom();
        }
        obj = method.invoke(targetObject, args);
        return obj;
    }    
    
    private void checkPopedom() {
        System.out.println("检查权限:checkPopedom()!");
    }
}
/**
 * 测试类
 */
public class ProxyTest {
    
    public static void main(String[] args) {
        UserManager userManager = (UserManager)new CGLibProxy().createProxyObject(new UserManagerImpl());
        System.out.println("CGLibProxy:");
        userManager.addUser("tom", "root");
        System.out.println("JDKProxy:");
        JDKProxy jdkProxy = new JDKProxy();
        UserManager userManagerJDK = (UserManager)jdkProxy.newProxy(new UserManagerImpl());
        userManagerJDK.addUser("tom", "root");
    }
}
// 运行结果
CGLibProxy:
检查权限checkPopedom()!
调用了UserManagerImpl.addUser()方法!
JDKProxy:
检查权限checkPopedom()!
掉用了UserManagerImpl.addUser()方法!

总结:1.JDK代理使用的是反射机制实现aop的动态代理,CGLIB代理使用字节码处理框架asm,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,cglib创建效率较低,执行效率高;2.JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLIB则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态代理的两种方式以及区别 的相关文章

  • 如何处理java.util.concurrent.ExecutionException异常?

    我的代码的某些部分抛出 java util concurrent ExecutionException 异常 我该如何处理这个问题 我可以使用 throws 子句吗 我对java有点陌生 这取决于您的任务关键程度Future是为了如何处理它
  • 协助持续进行 Java 到 C# 转换的工具

    如今 许多项目都是用 Java 编写的 其中一些最终转换为 C 以合并到 NET 中 我想到的例子有 log4net nhibernate 和 db4o 包括 Sharpen db4o 的工具 在内 您是否见过和 或使用过任何使连续转换变得
  • 如何从内容处置中读取编码的文件名

    我得到的内容处置标头值如下 附件 文件名 UTF 8 album jpeg 如何从中提取文件名 album jpeg 在查看该值时 它具有编码格式值 使用Spring的内容配置 https docs spring io spring doc
  • 删除 PriorityQueue 的顶部?

    假设我使用 Java util 中的 PriorityQueue 类 我想从 PriorityQueue pq 中删除最大的数字 我们假设它位于队列的头部 下面的工作会起作用吗 1 int head pq peek pq dequeue h
  • 为什么从 Eclipse 导出的可运行 JAR 不起作用?

    我有一个在 Eclipse 中运行良好的项目 但是 当我将其导出到可运行的 JAR 其中包含依赖项 时 它不会运行 从控制台运行 JAR 时出现的错误是 编辑 之前没有使用 jar 运行它 INFO Loading XML bean def
  • jUnit 中每个 @Test 的不同拆卸

    有没有办法为 jUnit 中的每个 Test 定义不同的拆卸 Use the After注释来指示每个之后要运行的方法 Test 像这样的全套注释是 BeforeClass 首先 Tests are run Before 在每个之前 Tes
  • 使用Keycloak保护Tomcat应用程序时出现HTTP 403禁止错误

    我为这个错误苦苦挣扎了一整天 我一遍又一遍地检查我在tomcat中Keycloak和APP的配置 没有发现错误 下图为测试场景 APP配置 1 Keycloak json是从Keycloak控制台复制的 2 context xml 也正确
  • Android - 使用 Intent 打开 PDF 文档关闭后不保存

    我面临的问题是 当尝试保存对使用此 URI 打开的 PDF 文档的更改时内容 xx xxx xxx fileprovider external Download Sync FileName pdf 我所做的任何更改在关闭文档后都不会保存 但
  • 检查 jar 是否从 shell 运行

    我有一个 java jar 程序 我试图在我的机器启动时运行它 理想情况下 shell 脚本将每 60 秒检查一次以确保 jar 正在运行 我如何检查 jar 是否在 centos 上运行 这似乎不起作用 我当前的 sh 文件 bin ba
  • 在 Java 中停止线程? [复制]

    这个问题在这里已经有答案了 我正在编写一段代码 该代码连接到服务器 使用该连接生成一堆线程并执行一堆 东西 在某些情况下 连接会失败 我需要停止一切并从头开始使用新对象 我想在对象之后进行清理 但在线程上调用 thread stop 但此方
  • 如何跨工作区保存 E​​clipse 启动配置文件?

    当我复制 Eclipse 项目目录时 它包含 classpath 和 project 文件 这样当我将同一目录带到另一个 Eclipse 实例时 我不必设置我的构建路径等 假设所有资源都包含在在项目中 而不是外部 但是 此过程不会导致启动配
  • 查找前 N 个五边形数

    我必须找到第一个N pentagonal numbers 1 从 1 100 并每行显示 10 个 我必须使用getPentagonalNumber int n 方法也是如此 显然这就是它存在的原因 到目前为止 这是我的代码 package
  • 如何更改使用 Google ReCaptcha 版本 2 时的错误消息?

    当为 Google ReCaptcha 版本 2 选择多张照片时 会显示以下错误消息 需要多个正确的解决方案 请解决更多 如何将错误消息更改为我网站上的自定义消息 这是图像 我认为不可能在服务器端 在谷歌 进行 这可以在客户端通过利用 js
  • 如何删除 Spring 的 RestTemplate 添加的某些 HTTP 标头?

    我在远程服务方面遇到问题 我无法控制对使用 Spring 的 RestTemplate 发送的请求进行 HTTP 400 响应 使用发送的请求curl但被接受了 所以我将它们与通过 RestTemplate 发送的内容进行了比较 特别是 S
  • 如果使用 Maven,是否应该忽略 VCS 中 Eclipse 特定的文件?

    我知道为什么不将 Eclipse IDE 特定的文件提交到像 Git 我实际上正在使用的 这样的 VCS 中 这就是我使用 Maven 并让它为您生成这些文件的原因之一not将它们置于版本控制之下 但我想知道 是否应该在 gitignore
  • 从 Spring 启动运行 Java 类

    我使用的是Java8和Spring4 3 1 我有一个 Java Spring 应用程序托管由浏览器和移动应用程序客户端访问的 RESTfult 服务 其次 我编写了一个侦听事件的聊天服务器 socket io 来自客户 该聊天服务器正在从
  • 如何列出所有已加载的 Spring bean 定义文件

    在大型企业系统中 并不总是清楚在 ApplicationContext 构建期间导入了哪些文件 有没有办法列出过程中加载的所有文件 我知道如何列出加载的属性文件 但不知道导入的 bean 文件 更新示例 文件 1 applicationCo
  • 使用用户名和密码登录 LinkedIn 失败

    LinkedIn使用oauth登录其api 服务器中无法登录api 我尝试使用http请求登录linkedin并获取oauth verifier 但我得到了这样的回应 很抱歉 出现了问题 你的申请 请确保您 启用cookie并重试 或点击此
  • Selenium 查看鼠标/指针

    有什么方法可以在运行测试时真正看到硒鼠标吗 要么是 Windows 光标图像 要么是某种点或十字线或任何东西 我正在尝试使用拖放功能selenium and java in an HTML5Web 应用程序 并且能够看到光标以了解它实际在做
  • Mac 上的 JavaFX WebView 字体问题

    有些网站显示乱码而不是正确的文本 它只发生在 Mac 上 For example with GMapsFX 可能与 OS X 10 11 或 10 12 有关 我用Java 1 8 0 121测试了它 此问题有任何修复或解决方法吗 就我而言

随机推荐

  • ubunut 远程备份整个系统到其他磁盘中

    ssh src ip sudo S dd if dev mmcblk0 dd of img status progress 压缩镜像
  • ESP8266恒温控制器

    本文 我们将使用ESP8266构建家用恒温器 温控器将具有以下功能 它将从DHT22温度传感器读取温度 它将温度与所需温度进行比较 如果高于它 它将触发继电器关闭 如果低于它 它将触发继电器打开 在此之前 首先了解下ESP8266如何保持温
  • mediapipe教程1:python代码

    一 背景 因为领导想用这个东西 因此开始研究 首先对于mediapipe的介绍不多说 百度一大堆 主要是 1 跨平台 2 对于移动设备友好 实时性足够 二 环境 因为对这东西不了解 这里先用python代码简单的看看效果 代码的参考网址 1
  • 零基础入门语义分割-地表建筑物识别-Task03:网络模型结构发展(3天)

    比赛地址 https tianchi aliyun com competition entrance 531872 introduction 本章主要讲解的是语义分割网络模型的发展 FCN SegNet Unet DeepLab Refin
  • QT-纯代码控件-QGridLayout(网格布局)

    实现一个简单的网格布局分布 1 新建一个无ui界面的工程 其基类为dialog 2 代码实现 dialog h和main cpp不做改变 dialog cpp include dialog h include
  • Excel重复查询

    工作中 经常对数据要求不重不漏 熟练用好基础工具很重要 比如 Excel筛选某一列的重复值方法 1 开始 gt 条件格式 gt 突出显示单元格规则 gt 重复值 2 写代码排查 重复的值会显示不一样的颜色 可肉眼观察到
  • SpringBoot与Spring的区别

    目录 Spring Boot 特性一 更快速的构建能力 Spring Boot 特性二 起步依赖 Spring Boot 特性三 内嵌容器支持 Spring Boot 特性四 Actuator 监控 Spring Boot 本质上是 Spr
  • Org.Hibernate.AnnotationException: No Identifier Specified For Entity I don't have a id in my table

    程序运行报错 Org Hibernate AnnotationException No Identifier Specified For Entity I don t have a id in my table Entity中 Id导包导错
  • linux 设置时区

    参考 https www cnblogs com librawhj p 8989755 html
  • 高频JMeter软件测试面试题

    近期 有很多粉丝在催更关于Jmeter的面试题 索性抽空整理了一波 以下是一些高频JMeter面试题 拿走不谢 一 JMeter的工作原理 JMeter就像一群将请求发送到目标服务器的用户一样 它收集来自目标服务器的响应以及其他统计数据 这
  • 《机器学习》(西瓜书)周志华学习思维导图——第六、七章

    本文主要介绍了机器学习中的常用算法支持向量机 SVM 和贝叶斯分类器 第六章 支持向量机 支持向量机是一种常用的分类模型 分类学习的基本思想就是基于训练集在样本空间找到一个划分超平面 将不同类别的样本分开 学习的目标是为了找到具有最大间隔的
  • 解决vue 微信JSSDK注入权限时出现“invalid signature”(ios)

    请求后台将当前页面的url传给后台 后台返回配置信息后使用wx config注入权限 安卓无任何问题 但是iOS一直无法无法正常运行 url里也没带有 号 打开debug查看提示的invalid signature 并且报错的url不是我当
  • SetThreadName & GetThreadName

    ypedef struct tagTHREADNAME INFO DWORD dwType must be 0x1000 LPCSTR szName pointer to name in user addr space DWORD dwTh
  • 2023 年博客之星的入围规则

    最近的活动 博客之星6月城市领跑比赛 CSDN 博客之星 是一年一度的博主评选 是平台对博主一年贡献的答谢 往年的博客之星均在年末进行 2023年我们进一步优化了博客之星的评选规则 让更多优质的博主更有机会上榜 也无需担心错过报名时间 以下
  • java获取汇率 美元-人民币

    import java io BufferedReader import java io DataOutputStream import java io IOException import java io InputStream impo
  • 第十三届“华中杯”大学生数学建模挑战赛题目 A 题 马赛克瓷砖选色问题

    第十三届 华中杯 大学生数学建模挑战赛题目 A 题 马赛克瓷砖选色问题 要求1 2 3用python完成 文章目录 第十三届 华中杯 大学生数学建模挑战赛题目 A 题 马赛克瓷砖选色问题 要求1 2 3用python完成 前言 一 算法构思
  • LibEvent中文帮助文档

    http blog csdn net zhouyongku article details 53431597 libevent源码分析 http blog csdn net yusiguyuan article details 182675
  • Rinetd 端口转发

    文章目录 端口转发工具 Rinetd 安装 利用 Rinetd 实现Service 负载均衡 端口转发工具 Rinetd Rinetd 重定向传输协议控制工具 可将源ip端口 数据转发至目标 ip端口 在 k8s 中用于将service服务
  • jwt实现token鉴权(nodejs koa)

    为什么需要token 在后台管理系统中 我们通常使用cookie session的方式用于鉴权 如何通过cookie session鉴权 nodejs koa 但这种方式存在着以下问题 比如cookie的容量太小 浏览器端和app端发送ht
  • 动态代理的两种方式以及区别

    JDK动态代理 利用反射机制生成一个实现代理接口的匿名类 在调用具体方法前调用InvokeHandler来处理 CGlib动态代理 利用ASM 开源的Java字节码编辑库 操作字节码 开源包 将代理对象类的class文件加载进来 通过修改其