CGLib 是一个强大、高性能和高质量的代码生成库,它用于在运行时扩展 Java 类和实现接口。CGLib 被广泛应用于 AOP 框架中,如:Spring Framework 框架,用以提供方法拦截操作。Hibernate 作为一个比较受欢迎的 ORM(对象关系映射)框架,同样使用CGLib 来代理单端(多对一和一对一)关联。
CGLib 作为一个开源项目,其代码托管在 github,地址为:
https://github.com/cglib/cglib
CGLib 代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。
我们知道 Java 中有一个动态代理也是做这个事情的,那我们为什么不直接使用 Java 动态代理,而要使用 CGLib 呢?答案是 CGLib 相比于 JDK 动态代理更加强大。JDK 动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么 JDK 动态代理就没法使用了。

图1:CGLib 组成结构
CGLib 底层使用了 ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。除了 CGLib 库外,脚本语言(如 Groovy 和 BeanShell)也使用 ASM 生成字节码。ASM 使用类似 SAX 的解析器来实现高性能。我们不鼓励直接使用 ASM,因为它需要对 Java 字节码的格式足够的了解。
上面说了这么多,你可能还是不知道 CGLib 是干什么的,下面通过一个具体的例子来介绍 CGLib 的用法。假如我们有一个 HelloWorld 类,该类有一个 test() 方法。然后,通过 CGLib 为 HelloWorld 创建一个代理对象,实现在调用 test() 方法前后打印字符串到控制台。代码如下:
(1)添加 Maven 依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
(2)HelloWorld.java 类
/**
* 被代理的类
* @author hxstrive.com 2021/12/29
*/
public class HelloWorld {
public void test(){
System.out.println("hello world");
}
}(3)CglibHello.java 类
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 第一个 CGLib 示例,使用 CGLib 创建 {@link HelloWorld} 类的代理对象
* @author hxstrive.com 2021/12/28
*/
public class CglibHello {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloWorld.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("before method run...");
Object result = proxy.invokeSuper(obj, args);
System.out.println("after method run...");
return result;
}
});
HelloWorld sample = (HelloWorld) enhancer.create();
sample.test();
}
}运行程序,输出如下:
before method run... hello world after method run...