java-动态代理(CGLib、JDK动态代理)

CGLIB

什么是CGLIb

  • CGLIB通过ASM来转换字节码并生成新的类。
  • 它可以实现在运行过程中,扩展java类或者实现java接口。
  • 它是对ASM的包装,简化了 开发难度。

CGLib是如何工作的

  1. 通过继承指定的类,在派生类中重写非final方法。
  2. 在生成代码的时候,通过反射获取被代理方法的Method对象,并同时生成被代理方法的代理对象。
  3. 在重写被代理方法时:根据回调过滤器选择具体的CallBack

Callback

回调过滤器

  • 继承并重写CallBackFilter类的accept方法,该方法接受一个Method对象
  • 函数中的int返回值,表示CallBack数组的索引位置。
  • 过滤器相当于绑定了方法的CallBack的映射关系。
public class TargetMethodCallbackFilter implements CallbackFilter {
 
    /**
     * 过滤方法
     * 返回的值为数字,代表了Callback数组中的索引位置,要到用的Callback
     */
    @Override
    public int accept(Method method) {
        if(method.getName().equals("method1")){
            System.out.println("filter method1 ==0");
            return 0;
        }
        if(method.getName().equals("method2")){
            System.out.println("filter method2 ==1");
            return 1;
        }
        if(method.getName().equals("method3")){
            System.out.println("filter method3 ==2");
            return 2;
        }
        return 0;
    }
 
}
public class TestCglib {
    public static void main(String args[]) {
        Enhancer enhancer =new Enhancer();
        enhancer.setSuperclass(TargetObject.class);
        CallbackFilter callbackFilter = new TargetMethodCallbackFilter();
        
        /**
         * (1)callback1:方法拦截器
           (2)NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。
           (3)FixedValue:表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。
         */
        Callback noopCb=NoOp.INSTANCE;
        Callback callback1=new TargetInterceptor();
        Callback fixedValue=new TargetResultFixed();
        Callback[] cbarray=new Callback[]{callback1,noopCb,fixedValue};
        //设置数组而不是单个回调
        //enhancer.setCallback(new TargetInterceptor());
        enhancer.setCallbacks(cbarray);
        enhancer.setCallbackFilter(callbackFilter);
        TargetObject targetObject2=(TargetObject)enhancer.create();
        System.out.println(targetObject2);
        System.out.println(targetObject2.method1("mmm1"));
        System.out.println(targetObject2.method2(100));
        System.out.println(targetObject2.method3(100));
        System.out.println(targetObject2.method3(200));
    }
}

1、FixedValue(固定值)

  • 不需要执行代理逻辑,返回固定值
/*****
 * 该callback相当于重写了相应的函数实现。并不会调用原函数
 */
public class FixValueCallback implements FixedValue {


    /*****
     * 被代理方法的指定函数将会无条件的返回改object,动态的变更返回值
     * @return
     * @throws Exception
     */
    public Object loadObject() throws Exception {
        System.out.println("this is fixvalue callback .....    overwrite the code....");
        return true;
    }
}

//产生的代码样例
public final void methodForFixValue() {
    FixedValue var10000 = this.CGLIB$CALLBACK_5;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_5;
    }
	//直接调用了FixValue callback的loadObject,相当于重写逻辑
    var10000.loadObject();
}

2、InvocationHandler

  • invoke方法中没有传入被代理对象本身
  • 防止无限循环调用的方式是,method方法传入的动态类型是基类(被代理对象),基类中的方法不会再调用invoke方法。
public class InvocationHandlerCallback implements InvocationHandler {
    /*****
     * invocationHandler的invoke方法传入的method和proxy都是代理本身对象
     * 切忌重复调用,会循环调用
     * @param proxy 代理类本身
     * @param method 被代理类的内部的方法
     * @param args  参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invocationHandlerCallback Before....");
        
        //proxy.getClass().getSuperclass().newInstance()获取父类对象
        //这个父类对象也可以在CallBack的构造函数中传入
        method.invoke(proxy.getClass().getSuperclass().newInstance(),args);
        
        //会无限循环,原因:动态类型指向了代理类,在代理中还会调用invoke
        //method.invoke(proxy,args);
        
        System.out.println("invocationHandlerCallback after....");
        return null;
    }
}


//产生的代码样例
public final void methodForInvocationHandler() {
    try {
        InvocationHandler var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }
		//调用InvocationHandler相应的invoke实现
        var10000.invoke(this, CGLIB$methodForInvocationHandler$4, new Object[0]);
    } catch (Error | RuntimeException var1) {
        throw var1;
    } catch (Throwable var2) {
        throw new UndeclaredThrowableException(var2);
    }
}

3、LazyLoader

  • 代理对象内部维护了一个被代理对象的引用,当需要访问被代理对象时,会在同步方法内判断该引用是否为空。
  • 如果为空,则会调用懒加载器生成被代理对象。
  • LazyLoader仅会在第一次访问被代理对象时调用,如果没有访问被代理对象,则不会产生该对象,实现懒加载。
  • 注意:懒加载是指被代理对象的懒加载,而不是被代理对象内部属性的懒加载。内部使用了synchronized,可能会存在性能问题
/****
 *
 * 延迟加载初始化
 * 类似于spring prototype的singleton ,在第一次调用的时候进行初始化,并且将此实例存储起来,之后都将返回改实例
 * 可参考资料:
 * https://shensy.iteye.com/blog/1881277
 */
public class LazyLoaderCallback implements LazyLoader {
    public Object loadObject() throws Exception {
        CallbackBean callbackBean = new CallbackBean();
        return callbackBean;
    }
}


//产生的代码样例
    public final String getKey() {
        //获取被代理对象,并调用父类方法
        return ((PropertyBean)this.CGLIB$LOAD_PRIVATE_0()).getKey();
    }

    private final synchronized Object CGLIB$LOAD_PRIVATE_0() {
        Object var10000 = this.CGLIB$LAZY_LOADER_0;
        if (var10000 == null) {
            LazyLoader var10001 = this.CGLIB$CALLBACK_0;
            if (var10001 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10001 = this.CGLIB$CALLBACK_0;
            }

            var10000 = this.CGLIB$LAZY_LOADER_0 = var10001.loadObject();
        }

        return var10000;
    }

Hibernate例子

  • 实体类

    public class PropertyBean {
        private String key;
        private Object value;
        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
        public Object getValue() {
            return value;
        }
        public void setValue(Object value) {
            this.value = value;
        }
        @Override
        public String toString() {
            return "PropertyBean [key=" + key + ", value=" + value + "]" +getClass();
        }
        
    }
    
  • 延迟加载器

    public class ConcreteClassLazyLoader implements LazyLoader {
        /**
         * 对需要延迟加载的对象添加代理,在获取该对象属性时先通过代理类回调方法进行对象初始化。
         * 在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化了(在CGLib的实现中只要去访问该对象内属性的getter方法,
         * 就会自动触发代理类回调)。
         */
        @Override
        public Object loadObject() throws Exception {
            System.out.println("before lazyLoader...");
            PropertyBean propertyBean = new PropertyBean();
            propertyBean.setKey("zghw");
            propertyBean.setValue(new TargetObject());
            System.out.println("after lazyLoader...");
            return propertyBean;
        }
     
    }
    
  • 生成代理对象

    //返回一个PropertyBean对象,不过这个对象是PropertyBean的代理对象
    //当访问代理对象的属性时(即调用GETTER),会触发被代理对象的初始化,调用loadObject方法返回真正的被代理对象
    private PropertyBean createPropertyBean() {
            /**
             * 使用cglib进行懒加载 对需要延迟加载的对象添加代理,在获取该对象属性时先通过代理类回调方法进行对象初始化。
             * 在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化了(在CGLib的实现中只要去访问该对象内属性的getter方法,
             * 就会自动触发代理类回调)。
             */
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(PropertyBean.class);
            PropertyBean pb = (PropertyBean) enhancer.create(PropertyBean.class,
                    new ConcreteClassLazyLoader());
            return pb;
        }
    

4、Dispatcher

  • 实现Dispatcher接口,要求实现loadObject方法,返回期望的代理类。值的一提的是,loadobject方法在每次调用被拦截方法的时候都会被调用一次
/****
 * 与lazy不同的是,每一次调用代理方法的时候,都会调用一次Dispatcher的loadObject获取对象
 * 而lazy则会缓存下来。
 */
public class DispatcherCallBack implements Dispatcher {
    public Object loadObject() throws Exception {
        CallbackBean callbackBean = new CallbackBean();
        return callbackBean;
    }
}


//CGLIB产生的代码
public final void methodForDispatcher() {
    Dispatcher var10000 = this.CGLIB$CALLBACK_3;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_3;
    }
	//每次都调用一次loadObject,获取对象,并调用对象的相应方法
    //这样的实现,相当于loadObject可以很灵活的返回相应的实现类或者子类
    ((CallbackBean)var10000.loadObject()).methodForDispatcher();
}

5、MethodInterceptor

public class MyMethodInterceptor implements MethodInterceptor{
 
    /**
     * sub:cglib生成的代理对象
     * method:被代理对象方法
     * objects:方法入参
     * methodProxy: 代理方法
     */
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        //method.invoke(sub,args);
        //invokeSuper会调用sub的基类的方法
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("======插入后者通知======");
        return object;
    }
}

//CGLib生成的代码
public final void methodForInterceptor() {
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_1;
    }

    if (var10000 != null) {
        //调用callback的intercept方法,用于实现拦截
        var10000.intercept(this, CGLIB$methodForInterceptor$1$Method, CGLIB$emptyArgs, CGLIB$methodForInterceptor$1$Proxy);
    } else {
        super.methodForInterceptor();
    }
}

6、NoOp

  • 通过接口声明了一个单例对象,该代理不对被代理类执行任何操作

样例

业务类

public class HelloService {
 
    public HelloService() {
        System.out.println("HelloService构造");
    }
 
    /**
     * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
     */
    final public String sayOthers(String name) {
        System.out.println("HelloService:sayOthers>>"+name);
        return null;
    }
 
    
    public void sayHello() {
        System.out.println("HelloService:sayHello");
    }
}

MethodInterceptor

public class MyMethodInterceptor implements MethodInterceptor{
 
    /**
     * sub:cglib生成的代理对象
     * method:被代理对象方法
     * objects:方法入参
     * methodProxy: 代理方法
     */
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        //method.invoke(sub,args);
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("======插入后者通知======");
        return object;
    }
}

method.invoke(sub,args)

  • sub代表的是动态生成的代理类,也就是说invoke方法参数实际的实际类型为代理类
  • 代理类的重写方法会调用拦截器的方法,导致死循环

生成CGLIB代理对象调用目标方法

public class Client {
    public static void main(String[] args) {
        // 代理类class文件存入本地磁盘方便我们反编译查看源码
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
        
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        
        // 设置enhancer对象的父类
        enhancer.setSuperclass(HelloService.class);
        
        // 设置enhancer的回调对象
        enhancer.setCallback(new MyMethodInterceptor());
        
        // 创建代理对象
        HelloService proxy= (HelloService)enhancer.create();
        
        // 通过代理对象调用目标方法
        proxy.sayHello();
    }
}

源码解析

反编译后代码

public class HelloService$$EnhancerByCGLIB$$be45efdd extends HelloService implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    //外部传递进来的拦截器
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$sayHello$0$Method;
    private static final MethodProxy CGLIB$sayHello$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;
 
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService$$EnhancerByCGLIB$$be45efdd");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService")).getDeclaredMethods())[0];
        CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
    }
 
    final void CGLIB$sayHello$0() {
        super.sayHello();
    }
 	//代理类动态重写的方法
    public final void sayHello() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
 
        if (var10000 != null) {
            var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
        } else {
            super.sayHello();
        }
    }
 
    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }
 
    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
 
        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }
 
    final String CGLIB$toString$2() {
        return super.toString();
    }
 
    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
 
        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
    }
 
    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }
 
    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
 
        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }
 
    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }
 
    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
 
        return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
    }
 
    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 1535311470:
            if (var10000.equals("sayHello()V")) {
                return CGLIB$sayHello$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }
 
        return null;
    }
 
    public HelloService$$EnhancerByCGLIB$$be45efdd() {
        CGLIB$BIND_CALLBACKS(this);
    }
 
    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }
 
    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }
 
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        HelloService$$EnhancerByCGLIB$$be45efdd var1 = (HelloService$$EnhancerByCGLIB$$be45efdd)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }
 
            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }
 
    }
 
    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
 
    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
 
    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }
 
    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }
 
        return var10000;
    }
 
    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }
 
    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }
 
    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }
 
    static {
        CGLIB$STATICHOOK1();
    }
}

样例

被代理对象

public class CallbackBean {

    public void methodForDispatcher(){
        System.out.println("methodForDispatcher...");
    }

    public void methodForFixValue(){
        System.out.println("methodForFixValue...");
    }

    public void methodForInvocationHandler(){
        System.out.println("methodForInvocationHandler...");
    }

    public void methodForLazy(){
        System.out.println("methodForLazy...");
    }

    public void methodForInterceptor(){
        System.out.println("methodForInterceptor...");
    }

    public void methodForNoop(){
        System.out.println("methodForNoop...");
    }
}

反编译分析

Dispatcher

public final void methodForDispatcher() {
    Dispatcher var10000 = this.CGLIB$CALLBACK_3;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_3;
    }
	//每次都调用一次loadObject,获取对象,并调用对象的相应方法
    //这样的实现,相当于loadObject可以很灵活的返回相应的实现类或者子类
    ((CallbackBean)var10000.loadObject()).methodForDispatcher();
}

FixedValue

public final void methodForFixValue() {
    FixedValue var10000 = this.CGLIB$CALLBACK_5;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_5;
    }
	//直接调用了FixValue callback的loadObject,相当于重写逻辑
    var10000.loadObject();
}

InvocationHandler

public final void methodForInvocationHandler() {
    try {
        InvocationHandler var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }
		//调用InvocationHandler相应的invoke实现
        var10000.invoke(this, CGLIB$methodForInvocationHandler$4, new Object[0]);
    } catch (Error | RuntimeException var1) {
        throw var1;
    } catch (Throwable var2) {
        throw new UndeclaredThrowableException(var2);
    }
}

LazyLoader

public final void methodForLazy() {
	//CGLIB$LOAD_PRIVATE_2在proxy初始化的时候初始化一次,并维护了该成员
	//与Dispatcher不同,每次调用都是运用proxy成员变量进行调用
    ((CallbackBean)this.CGLIB$LOAD_PRIVATE_2()).methodForLazy();
}

MethodInterceptor

public final void methodForInterceptor() {
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_1;
    }

    if (var10000 != null) {
        //调用callback的intercept方法,用于实现拦截
        var10000.intercept(this, CGLIB$methodForInterceptor$1$Method, CGLIB$emptyArgs, CGLIB$methodForInterceptor$1$Proxy);
    } else {
        super.methodForInterceptor();
    }
}

CGLib问题集合

内存溢出

  • 如果不使用缓存,将导致创建多个代理类,使方法区溢出
  • 解决方式:enhancer.setUseCache(true);

API

Enhancer

  1. 和Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。
  2. Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。
  3. Enhancer不能够拦截final方法,例如Object.getClass()方法,这是由于Java final方法语义决定的。基于同样的道理,Enhancer也不能对fianl类进行代理操作。这也是Hibernate为什么不能持久化final class的原因。
Enhancer enhancer = new Enhancer();
enhancer.setUseCache(true);
enhancer.setSuperclass(PropertyBean.class);
PropertyBean pb = (PropertyBean) enhancer.create(PropertyBean.class,
        new MyMethodInterceptor());
pb.getKey();

问题toString、hashCode报错

  1. CGLib会代理toString、hashCode等方法,如果CallBack的返回值不满足原函数要求可能报错,例如:
    1. FixedValue返回的是固定值,导致不会返回基类的hashCode;
    2. MethodInterceptor拦截方法后,修改了返回值。
  2. 解决方式:视具体情况,为toString、hashCode等方法添加执行的CallBack。

被代理对象有多个构造函数

  1. 先通过Enhancer获取class对象,并获取到构造器。
  2. 构造器在newInstance方法中通过参数类型、顺序去匹配具体的构造器。
  3. 但生成的构造函数不会调用CallBack

只对特定的方法执行代理

  1. 设置CallbackFilter,CallbackFilter中对于不执行代理的方法返回NoOp.INSTANCE

  2. Enhancer enhancer = new Enhancer();
    CallbackHelper callbackHelper = new CallbackHelper(PropertyBean.class, new Class[0]) {
        @Override
        protected Object getCallback(Method method) {
            if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class){
                return new FixedValue() {
                    @Override
                    public Object loadObject() throws Exception {
                        return "Hello cglib";
                    }
                };
            }else{
                return NoOp.INSTANCE;
            }
        }
    };
    enhancer.setCallbackFilter(callbackHelper);
    enhancer.setCallbacks(callbackHelper.getCallbacks());
    
  3. 也可以直接实现CallbackFilter接口

ImmutableBean

  • ImmutableBean允许创建一个原来对象的包装类,
  • 这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException。
  • 包装类不可变,但被代理对象可变。

POJO

public class SampleBean {
    private String value;

    public SampleBean() {
    }

    public SampleBean(String value) {
        this.value = value;
    }
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

Test

@Test(expected = IllegalStateException.class)
public void testImmutableBean() throws Exception{
    //创建被代理对象
    SampleBean bean = new SampleBean();
    bean.setValue("Hello world");
    
    //创建代理
    SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean); //创建不可变类
    Assert.assertEquals("Hello world",immutableBean.getValue()); 
    
    bean.setValue("Hello world, again"); //可以通过底层对象来进行修改
    Assert.assertEquals("Hello world, again", immutableBean.getValue());
    
    immutableBean.setValue("Hello cglib"); //直接修改将throw exception
}

Bean generator

  1. 在运行过程中创建类
  2. 可以设置类的基类、添加属性(同时添加get、set方法)
@Test
public void testBeanGenerator() throws Exception{
    BeanGenerator beanGenerator = new BeanGenerator();
    beanGenerator.addProperty("value",String.class);//添加属性
    Object myBean = beanGenerator.create();
    Method setter = myBean.getClass().getMethod("setValue",String.class);
    setter.invoke(myBean,"Hello cglib");

    Method getter = myBean.getClass().getMethod("getValue");
    Assert.assertEquals("Hello cglib",getter.invoke(myBean));
}

JDK动态代理

  1. Proxy根据类加载器和接口数组生成接口的实现类,在实现的方法中调用InvocationHandler的invoke方法。
  2. 在invoke方法中可以执行业务逻辑,(可以装配不同的实现类)

img

使用样例

  • 1、创建一个接口

    public interface HelloService {
        void sayHello();
    }
    
  • 第二步,实现接口

    public class HelloServiceImpl implements HelloService {
        @Override
        public void sayHello() {
            System.out.println("HelloService:sayHello");
        }
    }
    
  • 代理类:实现InvocationHandler

    public class HelloServiceIvtHandler implements InvocationHandler {
        public HelloService helloService;
    
        public void HelloServiceIvtHandler(HelloService helloService){
            this.helloService=helloService;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            method.invoke(helloService,args);
            return null;
        }
    }
    
  • 使用

    public class Main {
        public static void main(String[] args) {
            HelloService helloService = new HelloServiceImpl();
    
            //创建调用器,并装配被代理对象。具体什么时候装配被代理对象视具体情况而定。
            InvocationHandler handler = new HelloServiceIvtHandler(helloService);
    
            //根据上述对象创建新对象
            HelloService helloServiceProxy = (HelloService) Proxy.newProxyInstance(
                    helloService.getClass().getClassLoader(),
                    helloService.getClass().getInterfaces(),
                    handler);
    
            //调用
            helloServiceProxy.sayHello();
        }
    }
    

Proxy.newProxyInstance

   public static Object newProxyInstance(ClassLoader loader,//用哪个类加载器去加载代理对象
                                          Class<?>[] interfaces,//动态代理类需要实现的接口
                                          InvocationHandler h//动态代理方法在执行时,会调用h里面的invoke方法去执行
                                        )
        throws IllegalArgumentException

源码分析

  • newProxyInstance

        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    		//1、获取目标接口的克隆对象
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
             //2、根据接口:生成代理类对象
            Class<?> cl = getProxyClass0(loader, intfs);
    
            //使用指定的调用处理程序获取代理类的构造函数对象
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    			//
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                //3、如果Class作用域为私有,通过 setAccessible 支持访问
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                //4、获取Proxy Class构造函数,创建Proxy代理实例。
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }
    

局限性

  • 只能对该类所实现接口中定义的方法进行代理
posted @ 2021-03-15 13:58  code汤  阅读(199)  评论(0)    收藏  举报