首页 > 其他分享 >设计模式之cglib动态代理

设计模式之cglib动态代理

时间:2024-08-20 14:15:07浏览次数:5  
标签:动态 messi starName 代理 cglib 设计模式 public

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

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

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

 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动态代理了。

这里我要说两点,

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");

标签:动态,messi,starName,代理,cglib,设计模式,public
From: https://www.cnblogs.com/jilodream/p/18369362

相关文章

  • 设计模式反模式:UML图示与案例分析
    设计模式反模式:UML图示与案例分析在软件开发中,设计模式是解决问题的有效工具,它们通过提供经过验证的、可复用的解决方案来优化软件设计。然而,当设计模式被误用、滥用或在不适当的情况下应用时,就会形成设计模式反模式(Anti-Patterns)。这些反模式不仅不能解决问题,反而可能引入......
  • 设计模式六大原则 —— 迪米特法则
    设计模式六大原则——迪米特法则在软件设计领域,设计模式六大原则是一组被广泛接受和应用的指导原则,旨在帮助开发者构建更加稳定、灵活、可维护和可扩展的软件系统。这六大原则分别是:单一职责原则(SingleResponsibilityPrinciple,SRP)、开闭原则(Open-ClosedPrinciple,O......
  • 设计模式六大原则中的里氏替换原则
    设计模式六大原则中的里氏替换原则(LiskovSubstitutionPrinciple,LSP)是面向对象设计中一个至关重要的原则,它定义了继承的基本原则和约束,确保子类能够透明地替换父类,而不会破坏系统的正确性和稳定性。以下是对里氏替换原则的详细阐述,包括其定义、应用、重要性、以及在实际......
  • Java 设计模式
    23种设计模式创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模......
  • Docker compose 部署前后端-----采用nginx代理,支持一个端口部署多个前端
    Dockercompose部署前后端-----采用nginx代理,支持一个端口部署多个前端1、Linux服务器安装最新版docker,确保有dockercompose命令2、创建docker工作区目录mkdirdocker-workspace3、进入docker工作区目录,创建前端nginx目录,创建后端xxx目录mkdirnginxxxx4、创建confi......
  • 百度网盘代理怎么做?稳定收益,月入五位数
    在当前数字化时代,度盘作为一种流行的云存储服务,为用户提供了便捷、高效的数据存储和分享解决方案。然而,随着用户需求的不断增长,传统的网盘运营模式已无法满足部分用户的特殊需求。因此,度盘代理业务应运而生,它通过全新的思路和创新的策略,为代理商带来了稳定的收益,甚至实现了月入......
  • 设计模式实战:即时通讯应用的设计与实现
    系统功能需求用户管理:支持用户注册、登录、注销、个人信息更新等功能。消息传递:支持即时消息发送、接收、存储和显示,支持文本、图片、语音等多种消息类型。在线状态管理:实时跟踪和显示用户的在线状态。消息通知:在消息到达时发送推送通知给用户。聊天记录管理:支持聊天......
  • C# x Unity面向对象补全计划 设计模式 之 实现一个简单的有限状态机
    一个简单的有限状态机可以有如下内容1.状态基类(定义基本状态的方法,如进入(Enter)、执行(Execute)和退出(Exit),同时可以在此声明需要被管理的对象)2.具体状态类(定义具体状态,如:跳跃,行走,待机,每个具体状态类继承自状态基类)3.管理状态类(负责管理状态的切换逻辑,确保在不同状态之间进行......
  • 设计模式六大原则(二)--开闭原则
    1.简介1.1.概述开闭原则(Open/ClosedPrinciple,简称OCP)是软件设计原则中的一个重要原则,它指出:“软件实体(如类、模块、函数等)应该对扩展开放,对修改封闭。”这意味着我们应该设计出这样的软件实体,它们可以在不改变原有代码的基础上进行扩展和修改。开闭原则的核心思想是将......
  • WindowsServer系统下nginx代理问题
    部署vue打包后的dist文件夹后,重启nginx发现没生效,操作如下:1.停止redis,删除浏览器缓存并用无痕模式访问发现依然不生效,试着各种办法重新导入数据库数据也不行,nginx.exe-sstop依然能访问2.搜索发现可能是WindowsServer系统的问题,于是执行命令nginx-squit退出nginx......