Java中的Cglib代理
2018-03-23 19:04
162 查看
写在前面:
首先我们知道动态代理模式是实现AOP编程的核心,而动态代理这种设计模式又分为JDK代理和Cglib代理,在上一篇博客中,已经总结了JDK代理的实现过程(https://blog.csdn.net/may_3/article/details/79595432)。这篇博客,我们将总结Cglib代理,以及,这两种代理方式的区别,特点。
Cglib代理采用了asm框架的字节码技术。通过字节码技术为一个类创建一个子类。并且,在子类中采用方法拦截的技术,拦截所有父类方法的调用。
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; Enhancer、MethodInterceptor、MethodProxy这三个类和接口是我们实现Cglib动态代理的核心。
首先Enhancer类用于创建代理实例。负责整个代理对象的生命周期。
其中setSuperclass方法用于设置被代理对象。也就是代理对象的父类。public void setSuperclass(Class superclass)
{
if ((superclass != null) && (superclass.isInterface())) {
setInterfaces(new Class[] { superclass });
} else if ((superclass != null) && (superclass.equals(Object.class))) {
this.superclass = null;
} else {
this.superclass = superclass;
}
}
setCallback方法用于设置回调。也就是对我们代理的方法转发到这个回调上。且所有回调类必须实现MethodInterceptor接口,并且实现intercept方法。在intercept方法中,传递了4个参数:
(1)Object obj :被代理的源对象
(2)Method method :被代理的对象调用的方法
(3)Object [] args:被调用方法的参数集合
(4)MethodProxy proxy:被调用方法的代理,可以和method完成相同的事情,但是由于内部使用了FastClass机制,而不是反射,所以效率更高。
FastClass机制:
最后一步是调用create方法:
public class UserDao {
public void save() {
System.out.println("-----使用Cglib代理------");
}
}
Cglib代理核心类:package cglib;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class ProxyFactory implements MethodInterceptor {
public ProxyFactory(Object target) {
this.target = target;
}
// 维护一个目标对象,即被代理对象
private Object target;
// 为目标对象创建代理对象
public Object getProxyInstance() {
// 工具类
Enhancer en = new Enhancer();
// 设置父类
en.setSuperclass(target.getClass());
// 设置回调函数
en.setCallback(this);
// 创建子类
return en.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开启事务");
proxy.invokeSuper(obj, args);
System.out.println("提交事务");
return null;
}
}
调试:package cglib;
public class APP {
public static void main(String[] args) {
//目标对象
UserDao target=new UserDao();
System.out.println(target.getClass());
//代理对象
UserDao proxy=(UserDao) new ProxyFactory(target).getProxyInstance();
System.out.println(proxy.getClass());
proxy.save();
}
}
控制台输出:class cglib.UserDao
class cglib.UserDao$$EnhancerByCGLIB$$b5599079
开启事务
-----使用Cglib代理------
提交事务
这样我们就实现了Cglib代理。最后,再来看一下,JDK代理和Cglib代理的对比:
(1)JDK代理只能代理实现接口的类(因为生成的代理类的父类是Proxy类),而Cglib代理未接口的类。
(2)JDK代理使用反射机制,而Cglib使用ASM字节码生成框架,从效率上看,Cglib效率更高。
(3)Cglib不能对声明为final的方法进行代理,因为Cglib生成的代理类是被代理类的子类。
首先我们知道动态代理模式是实现AOP编程的核心,而动态代理这种设计模式又分为JDK代理和Cglib代理,在上一篇博客中,已经总结了JDK代理的实现过程(https://blog.csdn.net/may_3/article/details/79595432)。这篇博客,我们将总结Cglib代理,以及,这两种代理方式的区别,特点。
Cglib代理采用了asm框架的字节码技术。通过字节码技术为一个类创建一个子类。并且,在子类中采用方法拦截的技术,拦截所有父类方法的调用。
Cglib源码分析:
由于Cglib是第三方的API,所以需要导入相应的Jar包,因为自己是在学习Spring的时候,学习的Cglib代理,所以导入了Spring的核心jar文件,也就包括了Cglib代理的相关Jar文件。import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; Enhancer、MethodInterceptor、MethodProxy这三个类和接口是我们实现Cglib动态代理的核心。
首先Enhancer类用于创建代理实例。负责整个代理对象的生命周期。
其中setSuperclass方法用于设置被代理对象。也就是代理对象的父类。public void setSuperclass(Class superclass)
{
if ((superclass != null) && (superclass.isInterface())) {
setInterfaces(new Class[] { superclass });
} else if ((superclass != null) && (superclass.equals(Object.class))) {
this.superclass = null;
} else {
this.superclass = superclass;
}
}
setCallback方法用于设置回调。也就是对我们代理的方法转发到这个回调上。且所有回调类必须实现MethodInterceptor接口,并且实现intercept方法。在intercept方法中,传递了4个参数:
(1)Object obj :被代理的源对象
(2)Method method :被代理的对象调用的方法
(3)Object [] args:被调用方法的参数集合
(4)MethodProxy proxy:被调用方法的代理,可以和method完成相同的事情,但是由于内部使用了FastClass机制,而不是反射,所以效率更高。
FastClass机制:
//fastclassinfo类 private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; private FastClassInfo() {} FastClassInfo(MethodProxy.1 x0) { this(); } } public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = this.fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }在FastClassInfo类中,有4个参数f1表示被代理对象,f2表示代理对象,i1,i2是代理类中该方法的两个索引。而对于调用每一个代理方法的请求,都会转发到invokeSuper方法中。通过Hash索引的方式,找到方法,并调用方法,完成代理。
最后一步是调用create方法:
public Object create() { this.classOnly = false; this.argumentTypes = null; return createHelper(); }
private Object createHelper() { validate(); if (this.superclass != null) { setNamePrefix(this.superclass.getName()); } else if (this.interfaces != null) { setNamePrefix(this.interfaces[ReflectUtils.findPackageProtected(this.interfaces)].getName()); } return super.create(KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter, this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID)); }
Cglib实现动态代理的案例:
代理对象类:package cglib;public class UserDao {
public void save() {
System.out.println("-----使用Cglib代理------");
}
}
Cglib代理核心类:package cglib;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class ProxyFactory implements MethodInterceptor {
public ProxyFactory(Object target) {
this.target = target;
}
// 维护一个目标对象,即被代理对象
private Object target;
// 为目标对象创建代理对象
public Object getProxyInstance() {
// 工具类
Enhancer en = new Enhancer();
// 设置父类
en.setSuperclass(target.getClass());
// 设置回调函数
en.setCallback(this);
// 创建子类
return en.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开启事务");
proxy.invokeSuper(obj, args);
System.out.println("提交事务");
return null;
}
}
调试:package cglib;
public class APP {
public static void main(String[] args) {
//目标对象
UserDao target=new UserDao();
System.out.println(target.getClass());
//代理对象
UserDao proxy=(UserDao) new ProxyFactory(target).getProxyInstance();
System.out.println(proxy.getClass());
proxy.save();
}
}
控制台输出:class cglib.UserDao
class cglib.UserDao$$EnhancerByCGLIB$$b5599079
开启事务
-----使用Cglib代理------
提交事务
这样我们就实现了Cglib代理。最后,再来看一下,JDK代理和Cglib代理的对比:
(1)JDK代理只能代理实现接口的类(因为生成的代理类的父类是Proxy类),而Cglib代理未接口的类。
(2)JDK代理使用反射机制,而Cglib使用ASM字节码生成框架,从效率上看,Cglib效率更高。
(3)Cglib不能对声明为final的方法进行代理,因为Cglib生成的代理类是被代理类的子类。
相关文章推荐
- Java三种代理模式:静态代理、动态代理和cglib代理
- (转)Java动态代理与CGLib代理
- 谈谈java的代理模式认识 三————CGLIB代理
- java中的静态代理、动态代理以及Cglib代理
- IT忍者神龟之Java动态代理与CGLib代理
- IT忍者神龟之Java动态代理与CGLib代理
- java中的动态代理和CGLIB代理
- java 笔记(3) —— 动态代理,静态代理,cglib代理
- java 动态代理 和 cglib代理
- Java 动态代理以及Cglib代理
- java动静态代理与cglib代理
- java中的三种对象代理 静态代理动态代理及cglib代理
- Java动态代理与Cglib代理
- Java动态代理和CGLIB代理
- 谈谈java的代理模式认识 三————CGLIB代理
- cglib代理和java自带代理的区别
- 算法-蓝桥杯-算法训练 区间k大数查询(JAVA)
- 在Java中使用 Apache POI 处理Excel 文档详解
- java读入txt时去除两端的空格
- [Java] IO-02 BufferStream1 / BufferStream2