CGLib (Code Generation Library) 是一个强大的、高性能、高质量的 Code 生成类库(代码生成包)。它可以在运行期扩展 Java 类与实现 Java 接口。
静态代理和JDK动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
CGLib 比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅可以接管接口类的方法,还可以接管普通类的方法。
CGLIB的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。但不鼓励大家直接使用ASM框架,因为对底层技术要求比较高。
CASE需求: 机构报表任务统计,执行完成前置和后置增加打印日志,任务完成时间统计
类图
CglibProxyFactory
cglib代理构造工厂:
public final class CglibProxyFactory {
private CglibProxyFactory() {
}
public static <T> T getProxyInstance(T target, MethodInterceptor interceptor) {
Class<?> targetClass = target.getClass();
Enhancer enhancer = new Enhancer();
//设置类加载器
enhancer.setClassLoader(targetClass.getClassLoader());
//设置要代理的目标类,以扩展功能
enhancer.setSuperclass(targetClass);
// 设置单一回调对象,在回调中拦截对目标方法的调用
enhancer.setCallback(interceptor);
return (T) enhancer.create();
}
}
资源任务
public interface ResourceJob<T> {
String execute(T t) throws Exception;
}
真实主题
public class OrganizationIntervalReportStatisticJob implements ResourceJob<String> {
@Override
public String execute(String jobExecutionParam) throws Exception {
String message = String.format("org interval report job run arg:[%s]", jobExecutionParam);
System.out.println(message);
int time = new Random().nextInt(10) + 1;
Thread.sleep(time * 1000);
return Boolean.toString(true);
}
protected String executeTask(String jobExecutionParam) throws Exception {
String message = String.format("org interval report job run arg:[%s]", jobExecutionParam);
System.out.println(message);
int time = new Random().nextInt(10) + 1;
Thread.sleep(time * 1000);
return Boolean.toString(true);
}
public static String start(String jobExecutionParam) throws Exception {
String message = String.format("org interval report job run arg:[%s]", jobExecutionParam);
System.out.println(message);
int time = new Random().nextInt(10) + 1;
Thread.sleep(time * 1000);
return Boolean.toString(true);
}
}
ReportStatisticJobLogInterceptor
public class ReportStatisticJobLogInterceptor implements MethodInterceptor {
private Object target;
public ReportStatisticJobLogInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("the task start run");
Object result = method.invoke(target, args);
// Object result = proxy.invokeSuper(obj, args);
long stopTime = System.currentTimeMillis();
System.out.println("the task end run");
System.out.println("task run time ::" + (stopTime - startTime) + "毫秒!");
return result;
}
}
测试类
public class CglibProxyTest {
public static void main(String[] args) throws Exception {
OrganizationIntervalReportStatisticJob job = new OrganizationIntervalReportStatisticJob();
OrganizationIntervalReportStatisticJob proxyInstance = CglibProxyFactory.getProxyInstance(job, new ReportStatisticJobLogInterceptor(job));
String result = proxyInstance.execute("taskId=123");
System.out.println("resource task run result:" + result);
System.out.println("----------static test------------------");
OrganizationIntervalReportStatisticJob.start("taskId=456");
System.out.println("----------protected test------------------");
proxyInstance.executeTask("taskId=789");
}
}
执行结果:
分析:
Cglib实现动态代理的步骤也不是很麻烦,先创建一个类实现MethodInterceptor接口,重写intercept方法,在intercep中可以截获委托类的可代理的方法。
特点:
- 内存中动态的构建目标类的子类以达到代理的目的
局限性
- 目标类中方法如果有final/static,则不会被MethodInterceptor 拦截
- 目标类不能被final修饰,否则报异常(final修饰的类不能被继承)
Cglib动态代理与JDK动态代理对比:
相同的原理:
运行时动态生成代理对象,即通过编写代理的class文件,并将拦截的方法写入到代理的class中,在原有方法调用前,存在拦截器,则先调用拦截器的方法
区别:
1)JDK动态代理是Java原生支持的,不需要任何外部依赖,利用的是接口来实现的代理,目标类必须也只能实现某个或者某些接口;
2)Cglib则是利用继承关系,利用asm在运行时动态生成委托类的子类,从而实现对委托类的代理。因此不依赖接口
3)Cglib由于是利用继承关系来实现代理的,无论目标对象有没有实现接口都可以代理,但也因此无法代理被final修饰的类以及被final修饰的方法。
4)Cglib一般来说效率要比JDK动态代理效率更高,可以实现的代理也更为强大
应用
Hibernate 用它来实现 PO(ersistent Object 持久化对象) 字节码的动态生成
Spring AOP用它提供方法的interception(拦截)
本文暂时没有评论,来添加一个吧(●'◡'●)