CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它被许多 AOP 框架所使用,其底层是通过使用一个小而快的字节码处理框架 ASM(Java 字节码反编译框架)转换字节码并生成新的类。因此 CGLIB 要依赖于 ASM 的包,查看 Spring 的核心包 spring-core-5.2.5.RELEASE.jar,文件目录如图所示。

Spring5.2.5.RELEASE 版本的核心包已经集成了 CGLIB 所需要的包,所以在开发中不需要另外导入 ASM 的 JAR 包了。下面通过案例演示实现 CGLIB 代理实现上节案例的过程。
CGLIB 动态代理即支持接口也支持抽象类的方式实现。本节使用抽象类方式演示。
项目结构图如下:

1.设计演员抽象类
package com.entity;
public abstract class Actor {
protected String name; //演员的名字
protected String type; //出演影片的类型
public Actor() {
}
public Actor(String name, String type) {
this.name = name;
this.type = type;
}
//演戏抽象方法
public abstract void act() ;
}
2.设计影星类
package com.entity;
public class MovieStar extends Actor {
public MovieStar() {
}
public MovieStar(String name, String type) {
super(name, type);
}
public void act() {
System.out.println(this.name + "正在出演" + this.type + "影片...");
}
}
3.设计影星代理类
package proxy;
import com.entity.Actor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//成龙经纪人类(代理类)
public class ActorProxy implements MethodInterceptor {
// 目标对象
private Object targetObject; //成龙经纪人目标对象肯定是成龙
//传入一个代理之前的对象,返回一个被代理对象。
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(this.targetObject.getClass().getSuperclass());
// 设置enhancer的回调对象
enhancer.setCallback(this);
// 创建代理对象
return (Actor)enhancer.create();
}
//演戏之前要做的事情
private void beforeAct(){
System.out.println("洽谈档期..");
System.out.println("洽谈片酬..");
System.out.println("洽谈广告合作..");
}
//演戏之后要做的事情
private void afterAct(){
System.out.println("洽谈首映仪式..");
System.out.println("洽谈颁奖典礼..");
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object ret = null;
this.beforeAct();
//调用成龙真正的演戏方法
ret =method.invoke(this.targetObject,objects);
this.afterAct();
return ret;
}
}
4.测试类
package com.test;
import com.entity.Actor;
import com.entity.MovieStar;
import proxy.ActorProxy;
public class ActorDemo {
public static void main(String[] args) {
Actor actor = new MovieStar("成龙","功夫片");
actor = (Actor) new ActorProxy().newProxyInstance(actor);
actor.act();
}
}
运行结果:
洽谈档期..
洽谈片酬..
洽谈广告合作..
成龙正在出演功夫片影片...
洽谈首映仪式..
洽谈颁奖典礼..
MethodInterceptor 这个接口只有一个intercept()方法,这个方法有4个参数,含义如下:
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
1)obj表示增强的对象,即实现这个接口类的一个对象; 2)method表示要被拦截的方法; 3)args表示要被拦截方法的参数; 4)proxy表示要触发父类的方法对象;
感兴趣的同学可自行把Actor 设计为接口,实现效果完全相同。
JDK动态代理与CGLIB动态代理的区别
| 名称 | 区别 |
|---|---|
| jdk动态代理 | JDK动态代理只能对实现了接口的类生成代理,而不能针对类,例如:mybatis的mapper文件是代理。使用反射完成。使用了动态生成字节码技术。 |
| cglib动态代理 | CGLIB是针对类实现代理,接口和抽象类都可以使用,可以直接代理类,使用字节码技术,不能对 final类进行继承。使用了动态生成字节码技术。 |