什么是动态代理呢?
动态代理就是在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");

设计模式之cglib动态代理的更多相关文章

  1. Java代理(jdk静态代理、动态代理和cglib动态代理)

    一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 /** * 业务接 ...

  2. [z]Java代理(jdk静态代理、动态代理和cglib动态代理)

    一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 1 2 3 4 5 ...

  3. 代理模式 & Java原生动态代理技术 & CGLib动态代理技术

    第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...

  4. 017 Java中的静态代理、JDK动态代理、cglib动态代理

    一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...

  5. Cglib动态代理浅析

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2018-06-29/18.html 作者:夜月归途 出处:http://www.guitu ...

  6. JDK、CGlib动态代理详解

    Java动态代理之JDK实现和CGlib实现(简单易懂)      一 JDK和CGLIB动态代理原理 1.JDK动态代理 利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生 ...

  7. 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)

    代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...

  8. 基于SpringBoot实现AOP+jdk/CGlib动态代理详解

    动态代理是一种设计模式.在Spring中,有俩种方式可以实现动态代理--JDK动态代理和CGLIB动态代理. JDK动态代理 首先定义一个人的接口: public interface Person { ...

  9. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式, ...

  10. Spring事务Transactional和动态代理(二)-cglib动态代理

    系列文章索引: Spring事务Transactional和动态代理(一)-JDK代理实现 Spring事务Transactional和动态代理(二)-cglib动态代理 Spring事务Transa ...

随机推荐

  1. Linux安全审计之audit安装与使用

    场景 安全最重要的一步是内部安全,如何监控用户的行为是一个永恒不变的话题. audit可以详细监控用户的行为,详细到查看或修改了某个文件.这些都可以在日志中查看到. 安装 小贴士: CentOS默认已 ...

  2. Android自动化-如何获取视图元素属性?

    在做Android自动化时候,我们需要知道视图有哪些元素,元素都有哪些属性,获取到属性我们才能获取到元素从而做自动化控制,所以做Android自动化获取元素属性是必要的第一步 获取视图元素属性最便捷的 ...

  3. 实验2.ARP实验

    # 实验2.ARP实验 本实验用于验证arp以及arp表,arp缓存的使用,测试ping包时arp表的更新机制. 实验组 PC1 10.68.57.10 255.255.255.0 00-00-00- ...

  4. Nuxt3 的生命周期和钩子函数(八)

    title: Nuxt3 的生命周期和钩子函数(八) date: 2024/6/30 updated: 2024/6/30 author: cmdragon excerpt: 摘要:本文介绍了Nuxt ...

  5. 全志T3+FPGA国产核心板——Pango Design Suite的FPGA程序加载固化

    本文主要基于紫光同创Pango Design Suite(PDS)开发软件,演示FPGA程序的加载.固化,以及程序编译等方法.适用的开发环境为Windows 7/10 64bit. 测试板卡为全志T3 ...

  6. 【JavaScript】聊聊js中关于this的指向

    前言 最近在看回JavaScript的面试题,this 指向问题是入坑前端必须了解的知识点,现在迎来了ES6+的时代,因为箭头函数的出现,所以感觉有必要对 this 问题梳理一下,所以刚好总结一下Ja ...

  7. SpringCloud连接远程nacos报错,一直提示连接本地的localhost:8848

    application.properties spring.cloud.nacos.discovery.server-addr=xxx.xxx.xxx.xxx:8848 spring.applicat ...

  8. leetcode简单(数组、字符串):[219, 268, 349, 414, 485, 541, 557, 821, 925, 977]

    目录 219. 存在重复元素 268. 丢失的数字 349. 两个数组的交集 414. 第三大的数 485. 最大连续 1 的个数 541. 反转字符串 II 557. 反转字符串中的单词 III 8 ...

  9. oeasy教您玩转vim - 40 - # 复制粘贴

    ​ 复制粘贴 回忆上节课内容 我们上次的内容是粘贴 小写p意味着在光标下面或者后面粘贴 大写P意味着在光标上面或者前面粘贴 p的意思是放上去,就是put 把什么放上去呢? 把 reg 中 " ...

  10. 全网最适合入门的面向对象编程教程:20 类和对象的 Python 实现-组合关系的实现与 CSV 文件保存

    全网最适合入门的面向对象编程教程:20 类和对象的 Python 实现-组合关系的实现与 CSV 文件保存 摘要: 本文主要介绍了在使用 Python 面向对象编程时,如何实现组合关系,同时对比了组合 ...