首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

设计模式之cglib动态代理

编程知识
2024年08月20日 13:17

什么是动态代理呢?
动态代理就是在java进程运行时,通过字节码技术,动态的生成某个类的代理类。在这个代理类中,我们可以做一些额外的操作,一方面仍然保持原有的方法的能力,另外一方面还增强了这些能力。听着是不是AOP有点像,没错,动态代理就是AOP的技术基石。
在这之前我曾经写过两篇相关的文章:
https://www.cnblogs.com/jilodream/p/10611593.html 设计模式之代理模式
https://www.cnblogs.com/jilodream/p/10624940.html 设计模式之Jdk动态代理

而在实现动态代理时,一般会有两种办法:
jdk动态代理(可以点上文链接查看),以及cglib动态代理,
话不多说,我们直接来看如何使用cglib来动态代理:

例子我们还是使用和jdk动态代理相同的明星/明星代理类这个场景

pom依赖

1         <dependency>
2             <groupId>cglib</groupId>
3             <artifactId>cglib</artifactId>
4             <version>3.1</version>
5         </dependency>

明星类

 1 package com.example.demo.learncglib;
 2 
 3 import lombok.Data;
 4 import lombok.NoArgsConstructor;
 5 
 6 /**
 7  * @discription
 8  */
 9 
10 @Data
11 @NoArgsConstructor
12 public class SuperStar implements ISuperStar {
13     String starName;
14 
15     public SuperStar(String starName) {
16         this.starName = starName;
17     }
18 
19     @Override
20     public void signContract() {
21         System.out.println(starName + " 签名");
22         // to do sth
23         return;
24     }
25 
26     @Override
27     public void negotiate() {
28         System.out.println(starName + " 谈判");
29         // to do sth
30         return;
31     }
32 
33     @Override
34     public String getStarImage() {
35         System.out.println(starName + " start image");
36         // to do sth
37         return "One " + starName + " Image";
38     }
39 }

明星类接口

 1 package com.example.demo.learncglib;
 2 
 3 public interface ISuperStar
 4 {
 5     /**
 6      * 签约
 7      */
 8     void signContract();
 9 
10     void negotiate();
11 
12     String getStarImage();
13 }

代理工厂

 1 package com.example.demo.learncglib;
 2 
 3 
 4 import net.sf.cglib.core.DebuggingClassWriter;
 5 import net.sf.cglib.proxy.Enhancer;
 6 import net.sf.cglib.proxy.MethodInterceptor;
 7 import net.sf.cglib.proxy.MethodProxy;
 8 
 9 import java.lang.reflect.Method;
10 
11 /**
12  * @discription
13  */
14 public class ProxyFactory implements MethodInterceptor {
15 
16     private String starName;
17 
18     public SuperStar create(String starName) {
19         System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\code\\common\\learn-design" +
20                 "-pattern\\target\\cglib");
21 
22         this.starName = starName;
23         Enhancer enhancer = new Enhancer();
24         enhancer.setSuperclass(SuperStar.class);
25         enhancer.setCallback(this);
26         SuperStar proxy = (SuperStar) enhancer.create();
27         proxy.starName = starName;
28         return proxy;
29     }
30 
31 
32     @Override
33     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
34         System.out.println(starName + "的代理人开始组织活动");
35         Object obj = methodProxy.invokeSuper(o, objects);
36         System.out.println(starName + "的代理人结束组织活动");
37         return obj;
38     }
39 }

主类

 1 package com.example.demo.learncglib;
 2 
 3 /**
 4  * @discription
 5  */
 6 public class CglibMain {
 7     public static void main(String[] args) {
 8         ProxyFactory factory = new ProxyFactory();
 9         SuperStar superStar = factory.create("messi");
10         superStar.signContract();
11         superStar.negotiate();
12         String image=superStar.getStarImage();
13         System.out.println("we get a image: "+image);
14     }
15 
16 
17 }

运行效果

messi的代理人开始组织活动
messi 签名
messi的代理人结束组织活动
messi的代理人开始组织活动
messi 谈判
messi的代理人结束组织活动
messi的代理人开始组织活动
messi start image
messi的代理人结束组织活动
we get a image: One messi Image
Disconnected from the target VM, address: '127.0.0.1:64165', transport: 'socket'

生成代理类的核心逻辑在com.example.demo.learncglib.ProxyFactory#create方法中:

我们首先声明一个增强器:Enhancer enhancer
接着设置代理类父类:SuperStar.class
接着设置回调类(包含增强方法的类):? implements MethodInterceptor
最后调用增强类的创建方法就生成好了:enhancer.create()

整体的流程和jdk动态代理很像,

不同点是jdk动态代理是根据接口,动态的生成实现类,代理类和被代理类均为接口实现类,是“兄弟关系”,被代理的方法就是接口中公开的方法。
而cglib动态代理是将被代理类作为父类,派生出子类,代理类和被代理类均为继承关系,是“父子关系”,被代理的方法就是父类中公开的方法。
如下图:

其实细细想想也很正常,我们想要间接的动态的获取到某个类中公开的方法,有两种途径,第一种是继承自它,那么它所有的公开方法我们都能继续持有(cglib的思路)。第二种就是和他实现相同的约定(接口),那么它多有开发的协议,我们也就能动态的获取到了(jdk动态代理的思路)。

说了这么多来讲讲cglib方式的局限性,主要还是和继承有关系:
1、无法动态代理final方法,因为子类无法复写。

2、无法动态代理static,因为子类无法复写。
jdk动态代理和cglib可以说是各有优劣,很多人说经过jdk动态代理的速度优化,spring 目前已经默认采用jdk动态代理了,所以jdk动态代理更好。

这里我要说两点,

1、设计和实现是两回事,未来cglib的实现思路经过优化,又胜出了,也并不能说明cglib的设计方案更好;

2、目前的Springboot最新版本又采用了cglib作为默认的aop实现方式,这也并不能说明cglib就比jdk动态代理方式要强了。


ps:如果想要将运行时动态生成的class文件保存到磁盘中,可以在执行的代码出添加,如上文代码示例的红色字体处:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\code\\common\\learn-design-pattern\\target\\cglib");

From:https://www.cnblogs.com/jilodream/p/18369362
本文地址: http://www.shuzixingkong.net/article/1268
0评论
提交 加载更多评论
其他文章 PHP中的Malformed UTF-8 characters错误解决
在PHP开发中,开发者经常会遇到Malformed UTF-8 characters错误。这个错误通常是由于代码中存在无效的UTF-8字符而引起的。本篇博客将为您介绍如何解决这个问题。 什么是UTF-8字符? UTF-8是一种用于表示Unicode字符的编码方式。它可以表示任意Unicode字符,包
wifi基础(一):无线电波与WIFI信号干扰、衰减
liwen01 2024.08.18 前言 无论是在产品开发还是在日常生活中,在使用无线网络的时候,都会经常遇到一些信号不好的问题,也会产生不少疑问: 为什么我们在高速移动的高铁上网络会变慢? 为什么 5G WiFi 的穿墙能力没有 2.4G 的好? 为什么在对 WiFi 进行 iperf 拉距测试
wifi基础(一):无线电波与WIFI信号干扰、衰减 wifi基础(一):无线电波与WIFI信号干扰、衰减 wifi基础(一):无线电波与WIFI信号干扰、衰减
小小的引用计数,大大的性能考究
本文基于 Netty 4.1.56.Final 版本进行讨论 在上篇文章《聊一聊 Netty 数据搬运工 ByteBuf 体系的设计与实现》 中,笔者详细地为大家介绍了 ByteBuf 整个体系的设计,其中笔者觉得 Netty 对于引用计数的设计非常精彩,因此将这部分设计内容专门独立出来。 Nett
小小的引用计数,大大的性能考究 小小的引用计数,大大的性能考究 小小的引用计数,大大的性能考究
MySQL编译安装-麒麟V10 x86
环境信息 操作系统: Kylin Linux Advanced Server V10 (Sword) 架构:X86 MySQL版本:5.7.44 编译 安装必要的依赖库和编译工具 sudo yum groupinstall &#39;Development Tools&#39; sudo yum i
动态规划方法论
动态规划 动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的, 我在这里举一个典型的动态规划的问题——背包问题:
使用python-slim镜像遇到无法使用PostgreSQL的问题
前言 之前不是把 DjangoStarter 的 docker 方案重新搞好了吗 一开始demo部署是使用 SQLite 数据库的,用着没问题,但很快切换到 PostgreSQL 的时候就遇到问题了… 报错 docker 启动之后,app 容器报错 django.core.exceptions.Im
LLM应用实战: 产业治理多标签分类
本期的干货就是分享关于如何基于LLM实现数量多、层级多的多标签分类的实战经验,各位读者可以参考借鉴。
LLM应用实战: 产业治理多标签分类 LLM应用实战: 产业治理多标签分类
XSS 基本概念和原理介绍
XSS 基本概念和原理介绍 基本概念 跨站脚本攻击 XSS(Cross Site Scripting),为了不和层叠样式表 ( Cascading Style Sheets,CSS ) 的缩写混淆,故将跨站脚本攻击缩写为 XSS。 恶意攻击者 往 Web 页面里插入恶意 JavaScript 代码,
XSS 基本概念和原理介绍 XSS 基本概念和原理介绍 XSS 基本概念和原理介绍