cglib的简单使用

article/2025/10/31 13:47:01

一、前言

最近在看Spring的源码,其中有牵扯到cglib的相关内容,遂简单记录下cglib是如何使用的

二、原理(节选自网络)

CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

CGLIB缺点:对于final方法,无法进行代理。

三、一个核心类:Enhancer

Enhancer是CGLib的字节码增强器,可以方便的对非final类进行扩展,它动态创建了给定类型的子类但是拦截了所有非final的方法。

3.1、简单使用Enhancer

如何简单的使用Enhancer:,看下面的几个方法:

//设置需要代理的类
public void setSuperclass(Class superclass);
//设置一个Callback
public void setCallback(Callback callback);

Callback可以理解为我们需要对原始类方法做的增强处理。

看下面的一段代码:

public class CglibTest4 {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(QService.class);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("my callback");methodProxy.invokeSuper(o,objects);return o;}});QService service = (QService) enhancer.create();System.out.println("test1 方法~~~~~~~~~~~~~~");service.test1();System.out.println("test2 方法~~~~~~~~~~~~~~");service.test2();System.out.println("getClass 方法~~~~~~~~~~~~~~");service.getClass();System.out.println("hashCode 方法~~~~~~~~~~~~~~~");service.hashCode();}
}class QService {public void test1() {System.out.println("test1");}public void test2() {System.out.println("test2");}
}

结果:
在这里插入图片描述
注意:
Enhancer 生成的代理类拦截了所有非final的方法(上面的例子中,拦截了test1方法、test2方法、hashCode方法,却未拦截getClass方法)

3.2、只拦截部分方法

Enhancer会拦截原始类的所有非final方法,但是我们通常情况下只需要对部分方法(例如业务方法)进行一些增强。这个时候可以给Enhancer设置CallbackFilter。
还是用上面的例子,这次我们只对test1方法和test2方法进行增强。

public class CglibTest4 {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(QService.class);Callback[] callbacks = new Callback[2];callbacks[0] = NoOp.INSTANCE;callbacks[1] = (MethodInterceptor) (o, method, objects, methodProxy) -> {System.out.println("my callback");methodProxy.invokeSuper(o,objects);return o;};enhancer.setCallbackFilter(method -> {if (method.getName().equals("test1") || method.getName().equals("test2")){return 1;}else {return 0;}});enhancer.setCallbacks(callbacks);QService service = (QService) enhancer.create();System.out.println("调用test1 方法~~~~~~~~~~~~~~");service.test1();System.out.println("");System.out.println("调用test2 方法~~~~~~~~~~~~~~");service.test2();System.out.println("");System.out.println("调用getClass 方法~~~~~~~~~~~~~~");service.getClass();System.out.println("");System.out.println("调用hashCode 方法~~~~~~~~~~~~~~~");service.hashCode();}
}class QService {public void test1() {System.out.println("test1");}public void test2() {System.out.println("test2");}
}

结果:
在这里插入图片描述
注意以下几点:
1、设置了两个Callback
2、设置了一个CallbackFilter

Enhancer支持设置多个Callback,进行多种不同方式的增强,而CallbackFilter的作用就是帮助代理类找到某个方法需要的Callback。上面的例子中,第一个Callback什么也不会做,而第二个Callback则会针对test1方法和test2方法做一些增强。CallbackFilter是如何为方法匹配所需的Callback呢?是通过CallbackFilter的 int accept(Method var1)方法的返回值确定的,这个返回值对应Callback[]中的下标。

四、几种Callback

4.1、MethodInterceptor

MethodInterceptor,这是一个功能很强大的接口,它可以实现类似于AOP编程中的环绕增强(around-advice)。

第一次使用:

public class CglibTest {public static void main(String[] args){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyService.class);Callback[] callbacks = new Callback[3];callbacks[0] = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("default callback");methodProxy.invoke(o,objects);return o;}};callbacks[1] = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("callback1");methodProxy.invoke(o,objects);return o;}};callbacks[2] = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("callback2");methodProxy.invoke(o,objects);return o;}};enhancer.setCallbacks(callbacks);enhancer.setCallbackFilter(new CallbackFilter() {@Overridepublic int accept(Method method) {if(method.getName().equals("method1")){return 1;}else if(method.getName().equals("method2")){return 2;}return 0;}});MyService myService = (MyService) enhancer.create();myService.method1();myService.method2();}}class MyService {public void method1() {System.out.println("method1 execute");}public void method2() {System.out.println("method2 execute");}
}

本意是创建三个callback,method1用callback[1]来增强,method2用callback[2]来增强,但是却出现了这样的结果:
在这里插入图片描述
原因是出现了循环调用:callback1()->intercept()->callback1()->intercept()->… 最后导致栈溢出
后来修改成使用invokeSuper()正常运行:

public class CglibTest {public static void main(String[] args){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyService.class);Callback[] callbacks = new Callback[3];callbacks[0] = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("default callback");methodProxy.invokeSuper(o,objects);return o;}};callbacks[1] = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("callback1");methodProxy.invokeSuper(o,objects);return o;}};callbacks[2] = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("callback2");methodProxy.invokeSuper(o,objects);return o;}};enhancer.setCallbacks(callbacks);enhancer.setCallbackFilter(new CallbackFilter() {@Overridepublic int accept(Method method) {if(method.getName().equals("method1")){return 1;}else if(method.getName().equals("method2")){return 2;}return 0;}});MyService myService = (MyService) enhancer.create();myService.method1();myService.method2();}}class MyService {public void method1() {System.out.println("method1 execute");}public void method2() {System.out.println("method2 execute");}
}

注意:MethodInterceptor的实现方法中应该调用invokeSuper方法,避免出现循环调用

4.2、FixedValue

使用FixedValue可以很容易的替换掉方法的返回值。

public class CglibTest2 {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MService.class);enhancer.setCallback(new FixedValue() {@Overridepublic Object loadObject() throws Exception {return "new method1";}});MService mService = (MService) enhancer.create();System.out.println(mService.method1());}
}class MService {public String method1() {return "method1";}}

结果:
在这里插入图片描述

4.3、NoOp

啥都不干,只是调用原来的方法

public class CglibTest2 {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MService.class);enhancer.setCallback(NoOp.INSTANCE);MService mService = (MService) enhancer.create();System.out.println(mService.method1());}
}class MService {public String method1() {return "method1";}}

在这里插入图片描述

4.4、LazyLoader

它提供了一个方法:Object loadObject() throws Exception;,loadObject()方法会在第一次被代理类的方法调用时触发,它返回一个代理类的对象,这个对象会被存储起来然后负责所有被代理类方法的调用,就像它的名字说的那样,一种lazy模式。如果被代理类或者代理类的对象的创建比较麻烦,而且不确定它是否会被使用,那么可以选择使用这种lazy模式来延迟生成代理。

public class CglibTest3 {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Person.class);enhancer.setCallback((LazyLoader) () -> {try{System.out.println(" before lazyloader");return new Person("lg");}finally {System.out.println(" after lazyloader");}});Person person = (Person) enhancer.create();System.out.println(person.getName());System.out.println(person.getName());System.out.println(person.getName());}}class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public Person(){}
}

结果:
在这里插入图片描述
如果把下面的代码注掉,则Person不会实例化:

       //System.out.println(person.getName());//System.out.println(person.getName());//System.out.println(person.getName());

结果:
在这里插入图片描述

4.5、Dispatcher

Dispatcher和LazyLoader接口相同,也是提供了loadObject()方法,这个方法同样地返回一个代理对象,这个对象同样可以代理原方法的调用。不过它们之间不同的地方在于,Dispatcher的loadObject()方法在每次发生对原方法的调用时都会被调用并返回一个代理对象来调用原方法。也就是说Dispatcher的loadObject()方法返回的对象并不会被存储起来,可以类比成Spring中的Prototype类型,而LazyLoader则是lazy模式的Singleton。

public class CglibTest3 {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Person.class);enhancer.setCallback((Dispatcher) () -> {try{System.out.println(" before lazyloader");return new Person("lg");}finally {System.out.println(" after lazyloader");}});Person person = (Person) enhancer.create();System.out.println(person);System.out.println(person);}}class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public Person(){}
}

结果:
在这里插入图片描述
即,通过Dispatcher生成的对象,每次调用的时候,代理都会重新再执行一次loadObject方法

参考

  • https://www.jianshu.com/p/20203286ccd9
  • https://blog.csdn.net/Q_AN1314/article/details/79724334

http://chatgpt.dhexx.cn/article/OROPSqLd.shtml

相关文章

cglib动态代理

前面介绍了代理模式和JAVA动态代理,这片文章主要解析cglib动态代理实现。 基本介绍 CGLIB(Code Generation Library),是一个强大的,高性能,高质量的 Code 生成类库,它可以在运行期扩展 Java 类…

动态代理之 cglib 实现

(尊重劳动成果,转载请注明出处:https://blog.csdn.net/qq_25827845/article/details/87513102冷血之心的博客) 目录 前言: 正文: AOP(面向切面编程) JDK动态代理 cglib实现动态…

CGLIB介绍与原理

一、什么是 CGLIB? CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个…

CGLIB(Code Generation Library)详解

什么是CGLIB CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)…

【动态代理】CGLIB 动态代理的使用及原理

1. CGLIB 动态代理介绍 什么是 CGLIB? CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。 通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更…

CGLIB详解(最详细)

转载地址:https://blog.csdn.net/danchu/article/details/70238002 什么是CGLIB CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架&#xff0c…

GPG error解决方案

问题: sudo apt-get update时报错GPG error 解决方案: // F42ED6FBAB17C654是根据你报错那一行确定的 sudo gpg --keyserver keyserver.ubuntu.com --recv F42ED6FBAB17C654 sudo gpg --export --armor F42ED6FBAB17C654 | sudo apt-key add -然后: sudo apt-get update

GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

阿里云CentOS 7.9 64位 搭建网站踩坑实录 问题1.GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql Failing package is: mysql-community-libs-compat-5.7.37-1.el7.x86_64 GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql …

gpg文件加密解密

使用Ubuntu对文件进行gpg格式的加密和解密 安装 下载源码安装  ./configure   make   make install 命令安装 Debian环境 sudo apt-get install gnupg Fedora 环境 yum install gnupg 加密 gpg -c abc.txt 会让输入一个加密的密码,需要自己输入 解密 gpg -o …

GPG(GnuPG)的安装和使用

基于网络的开源项目,能给用户带来在公共标准基础上的自由发挥,并且能很好地给每个自愿人士提供了共享贡献的机会。但是,同时也因为大众化给使用共享的程序员或团队带来了安全性问题。 当程序员从中央仓库下载第三方构件的时候,下载…

gpg使用

https://blog.csdn.net/weixin_42559321/article/details/82147888 https://www.cnblogs.com/wanghongli/archive/2018/01/08/8241809.html rpm2cpio *.rpm | cpio -imd       #解压一个rpm包rpm -ivh *.rpm --force       #强制安装这个rpm包rpm -iv…

如何在Git中使用GPG

开篇之前,先给大伙看点东西 是不是很想要?你找对地方了! 下面是教程: 在 “开始”菜单 打开Git Bash 输入 gpg --gen-key 显示如下 $ gpg --gen-keygpg (GnuPG) 2.2.13-unknown; Copyright (C) 2019 Free Software Foundation, Inc.This …

成功解决gpg: 找不到有效的 OpenPGP 数据

在Ubuntu系统上安装docker时出现gpg: 找不到有效的 OpenPGP 数据的报错 解决方案: wget https://download.docker.com/linux/ubuntu/gpg sudo apt-key add gpg随后再次执行下载指令,解决报错 成功解决gpg: 找不到有效的 OpenPGP 数据的报错 欢迎小伙…

GPG Overview

Overview PGP目前支持的算法 非对称算法: RSA, ELG, DSA, ECDH, ECDSA, EDDSA对称算法: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256哈希算法: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224压缩算法: Uncompres…

GPG 使用初步

GPG 使用初步 1. PGP 软件的安装 PGP 的版本有很多,但由于其商业软件的特性,不能自由使用,自由软件基金会决定开发一个 PGP 的替代品,取名为 GnuPG ,这就是 PGP 的由来   GPG 是基于命令行的程序,主要面…

gpg加解密软件学习

为什么要学习gpg呢?因为要在Linux下把一个邮箱的密码加密,不让其他人看到该邮箱真正的密码。 为了不让其他人看到真正的邮箱密码,我们需要对其进行加密。 加密的方式是先把密码先写到一个文件A中,然后使用相关的加密软件对该文件…

java动态代理

java动态代理实现与原理详细分析 原文地址 关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。 一、代理模式 代理模式是常用的java…

动态规划 --- 算法思想介绍

一.动态规划的基本概念 动态规划在五种算法设计方法中难度最大,它建立在最优原则的基础上.采用动态规划方法,可以高效地解决许多用贪婪算法或分治法无法解决的问题.动态规划(dynamic programming)属运筹学中的规划论分支,是求解决策过程最优…

动态规划算法详解

动态规划算法通常用于求解具有最优性质的问题 基本概念 动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划(DP)。…

动态规划原理

1. 基本概念 动态规划通过拆分问题,将问题拆分成许多的子问题,定义问题状态和状态之间的关系(即状态转移方程或递推公式),使得问题能够以递推(或者说分治)的方式去解决。按顺序求解子问题&…