CGLIB动态代理
此文是不知道何时总结的,可能有不严谨的地方,仅供参考备份用,日后再修改。
和基于JDK的动态代理不同的是:
-
JDK争对接口进行动态代理,代理类和委托类共同实现同一个接口,只代理接口中声明的方法;
-
CGLIB动态代理依赖于CGLIB的类库需要配置依赖,实现原理上,CGLIB动态代理争对继承进行代理,代理类继承于委托类;
CGLIB动态代理简单演示
//委托类
public class CglibTest {
public void show1(){
System.out.println("show1.....");
}
}
//代理类的拦截器
public class CglibTestProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用了intercept()1");
Object obj=methodProxy.invokeSuper(o,objects);
System.out.println("调用了intercept()2");
return obj;
}
public Object getProxyObj(Class<?> clazz){
Enhancer enhancer=new Enhancer();
//设置代理类的父类即委托类
enhancer.setSuperclass(clazz);
//设置代理类的拦截器即本类
enhancer.setCallback(this);
//创建代理类
return enhancer.create();
}
}
//测试类
public class ProxyTest {
public static void main(String[] args) {
CglibTestProxy cglibTestProxy = new CglibTestProxy();
CglibTest proxyObj = (CglibTest) cglibTestProxy.getProxyObj(CglibTest.class);
proxyObj.show1();
}
}
在讲CGLIB原理之前,讲一下FastClass:
**为一个对象A创建它的FastClass对象,这个FastClass对象相当于A的方法索引,根据A的方法名生成并关联一个index、每个index对应A的一个方法。后续只要根据这个index以及A的实例,就可以调用fastClass的
invoke(instanceOfA, index, args)
方法来快速的调用A的方法了。实现了Java反射的“运行时动态调用指定类的方法”的功能,但是使用了不同的机制。**我们知道,java反射调用方法是比较“重”的操作,要经过一系列的权限验证、通过native方法请求jvm去方法区查找方法定义、以及最后的invoke仍然可能要通过JNI调用native方法。而相比之下,FastClass方式则跟一般的一个普通的对象方法调用没啥区别、只是多了一步根据index判断调用委托类的哪个方法这一步骤、性能损耗基本没有。
示例:
//普通类
public class Demo {
private double num1;
private double num2;
public Demo(double num1, double num2) {
this.num1 = num1;
this.num2 = num2;
}
public Demo() {
}
//加方法
public void add(){
System.out.println(num1+num2);
}
//减方法
public void subtract(){
System.out.println(num1-num2);
}
}
//FastClass类
public class DemoFastClass {
//方法名与一个索引关联
public int getIndex(String methodName){
switch (methodName){
case "add":return 0;
case "subtract":return 1;
default:return -1;
}
}
//实现方法
public Object invoke(int index,Object obj,Object[] objs){
Demo demo=(Demo)obj;
switch (index){
case 0:demo.add();return null;
case 1:demo.subtract();return null;
default:return null;
}
}
}
//测试类
public class FastClassTest {
public static void main(String[] args) {
Demo demo=new Demo(8,7);
DemoFastClass demoFastClass=new DemoFastClass();
int index = demoFastClass.getIndex("add");
demoFastClass.invoke(index,demo,null);
}
}
按理来说,用一个类的Class对象就可以构造类的FastClass,再拥有类的方法名就可以执行方法
原理:
生成的代理类(DemoEnhancerByCGLIBfbca2ec6)拥有一个拦截器的引用,委托类中的每一个方法(假设是fangfa())都对应生成的代理类中的两个属性
//CGLIB$fangfa$0$Method是通过反射机制获取的委托类的fangfa()方法
private static final Method CGLIB$fangfa$0$Method;
//CGLIB$fangfa$0$Proxy
private static final MethodProxy CGLIB$fangfa$0$Proxy;
和两个方法
//重写了父类方法
public final void fangfa(){....拦截器.intercept();...}
public void CGLIB$fangfa$0(){super.fangfa();}
CGLIB$fangfa 0 0 0Proxy的生成过程
Class class1 = Class.forName("Demo$$EnhancerByCGLIB$$fbca2ec6");
Class class2 = Class.forName("Demo")
//参数1:委托类Class对象;参数2:代理类Class对象;参数3:方法返回值;参数4:委托类中的方法名;参数5:代理类中的方法名
CGLIB$eat$0$Proxy = MethodProxy.create(class2, class1, "()V", "fangfa", "CGLIB$fangfa$0");
MethodProxy类的属性:
private Signature sig1;//委托类的方法信息(方法名,返回值)
private Signature sig2;//代理类类的方法信息(方法名,返回值)
private MethodProxy.CreateInfo createInfo;//委托类和代理类的Class对象
private final Object initLock = new Object();//锁
private volatile MethodProxy.FastClassInfo fastClassInfo;//FastClass信息(委托类和代理类的FastClass的对象和两个方法的索引
MethodProxy的invokeSuper():
//配合下面的init()理解
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
//初始化MethodProxy对象,创建FastClass对象和获得对应方法索引
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
//代理类的FastClass对象实现代理类的CGLIB$fangfa$0()方法,从而实现了super.fangfa()即委托类的fangfa()
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
init():
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
//helper()是构造FastClass的方法,通过委托类和代理类的Class对象构造其FastClass对象
fci.f1 = helper(ci, ci.c1);//委托类FastClass对象
fci.f2 = helper(ci, ci.c2);//代理类FastClass对象
fci.i1 = fci.f1.getIndex(this.sig1);//getIndex方法获得对应的索引值<fangfa()>
fci.i2 = fci.f2.getIndex(this.sig2);//getIndex方法获得对应的索引值<CGLIB$fangfa$0()>
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
在调用代理类中的fangfa()时,会被拦截器拦截转到intercept()中,这是我们实现的intercept()
@Override
//参数1:最终实现方法的实体,是代理类的实例,最终实现了CGLIB$fangfa$0();
//参数2:委托类中的方法即上文中的CGLIB$fangfa$0$Method;
//参数3:方法参数;
//参数4:方法代理即上文中的CGLIB$fangfa$0$Proxy
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用了intercept()1");
Object obj=methodProxy.invokeSuper(o,objects);
System.out.println("调用了intercept()2");
return obj;
}