4.CGLIB动态代理代码示例

564 阅读9分钟

实现动态代理的几种方案

  • javasisit(dubbo)
  • jdk 动态代理(jdk)
  • cglib(spring)
  • asm(cglib 内部也是用asm更改其字节码)

Cglib的动态代理

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供方法的interception(拦截)。

CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

实际上,cglib基于继承实现,这也就意味着final,private相关的method无法被代理,并且被final修饰的类也无法被代理。

基于asm框架对class字节码编辑改动,从而达到动态代理的目的,总之,被代理类没有实现接口的情况下cglib为首选。

cglib与jdk动态代理相比,除了可以代理实现接口的类也可以代理非实现接口的类,所以以后不要再说cglib只能对非实现接口的类做代理了。

cglib通过fastclass类来避免了java反射的使用。对jdk7以前的版本来说,jdk动态代理执行效率明显要比cglib动态代理类效率差,jdk8即以后版本对jdk动态代理进行了相应的优化,这种差距就不那么明显了。

cglib代理示例代码

package cglib;
/***
 * @author: claude
 * @date: 2023/3/3
 * @description: 
 */
public class Calculator {
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }
}
package cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/***
 * @author: claude
 * @date: 2023/3/3
 * @description:
 */
public class CalculatorMethodInterceptor implements MethodInterceptor {

    private Calculator target;

    public CalculatorMethodInterceptor(Calculator target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        for (Object object : args) {
            System.out.println("计算参数:" + object);
        }
        //下面2种写法都可以 
        Object result = methodProxy.invokeSuper(proxy, args);
        Object invoke = method.invoke(target, args);
        System.out.println("计算结果:" + result);
        System.out.println("计算结果:" + invoke);
        return result;
    }
}
package cglib;

import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
/***
 * @author: claude
 * @date: 2023/3/3
 * @description:
 */
public class CalculatorProxyFactory {
    public static void main(String[] args) {
        //动态代理创建的class文件存储到本地
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "e:\\proxy");
        //通过cglib动态代理获取代理对象的过程,创建调用的对象
        Enhancer enhancer = new Enhancer();
        //设置enhancer对象的父类
        enhancer.setSuperclass(Calculator.class);
        //设置enhancer的回调对象
        enhancer.setCallback(new CalculatorMethodInterceptor(new Calculator()));
        //创建代理对象
        Calculator calculator = (Calculator) enhancer.create();
        //通过代理对象调用目标方法
        calculator.add(1, 1);
    }
}

MethodInterceptor

利用cglib实现动态代理的时候,必须要实现MethodInterceptor接口,此接口源码如下:

package net.sf.cglib.proxy;
public interface MethodInterceptor extends Callback{
 		/*
        此方法用来实现方法的拦截,四个参数分别表示的含义:
        obj:cglib生成的代理对象实例
        method: 被代理对象的原始方法
        args:被代理对象的原始方法入参
        proxy:被代理对象的原始方法对应的MethodProxy
        调用时:Object result = methodProxy.invokeSuper(proxy, args);
        或者注入被代理类
        调用时:
 		*/
    public Object intercept(Object proxy, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}

除了使用MethodInterceptor,我们还可以使用其他的callback为被代理类做增强。

Callback简介

这里的callback可以认为是cglib用于生成字节码的实现手段,cglib一共实现了6种callback,用于对代理类目标进行不同手段的代理,非常灵活,分别为:

NoOp

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

package org.springframework.cglib.proxy;

public interface NoOp extends Callback {
    NoOp INSTANCE = new NoOp() {
    };
}

FixedValue

实现FixedValue接口,该callback同样要求实现一个loadobject方法,只不过需要注意的是该loadobject方法相同与重写了被代理类的相应方法,因为在被代理之后,FixedValue callback只会调用loadobject,而不会再调用代理目标类的相应方法!

package cglib.callback;

import org.springframework.cglib.proxy.FixedValue;

/*****
 * 该callback相当于重写了相应的函数实现。并不会调用原函数
 */
public class FixValueCallback implements FixedValue {
    /*****
     * 被代理方法的指定函数将会无条件的返回改object,动态的变更返回值
     * @return
     * @throws Exception
     */
    @Override
    public Object loadObject() throws Exception {
        return "return FixValueCallback";
    }
}

InvocationHandler

需要实现InvocationHandler接口,实现invoke对象,该拦截传入了proxy对象,用于自定义实现,与MethodInterceptor相似,慎用method的invoke方法。切忌不要造成循环调用

package cglib.callback;


import org.springframework.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;

public class InvocationHandlerCallback implements InvocationHandler {
    /*****
     * invocationHandler的invoke方法传入的method和proxy都是代理本身对象
     * 切忌重复调用,会循环调用
     * @param proxy 代理类本身
     * @param method 代理类内部的方法
     * @param args  参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invocationHandlerCallback Before....");
        //InvocationHandler用的居然是直接创建1个父类的实例
        method.invoke(proxy.getClass().getSuperclass().newInstance(),args);
        //会无限循环
        //method.invoke(proxy,args);
        System.out.println("invocationHandlerCallback after....");
        return "return invocationHandlerCallback";
    }
}

MethodInterceptor

实现MethodInterceptor的intercept,实现被代理对象的逻辑植入。也是最常用的callback.

package cglib.callback;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/****
 * 生成代理类字节码。对方法进行拦截调用
 */
public class MethodInterceptorCallback implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

        System.out.println("MethodInterceptor before invoke........");
        //MethodInterceptor用的是fastclass
        proxy.invokeSuper(obj,args);
        System.out.println("MethodInterceptor after invoke.........");
        return "return MethodInterceptor ";
    }
}

LazyLoader

实现LazyLoader的loadObject方法,返回对象实例,该实例只有第一次调用的时候进行初始化,之后不再重新调用,proxy类初始化时进行了成员的赋值,之后使用该成员进行调用父类方法

package cglib.callback;

import org.springframework.cglib.proxy.LazyLoader;

/****
 *
 * 延迟加载初始化
 * 类似于spring prototype的singleton ,在第一次调用的时候进行初始化,并且将此实例存储起来,之后都将返回该实例
 * 可参考资料:
 * https://shensy.iteye.com/blog/1881277
 */
public class LazyLoaderCallback implements LazyLoader {
    @Override
    public Object loadObject() throws Exception {
        Object callbackBean = new CallbackBean();
        System.out.println("LazyLoaderCallback.loadObject");
        return callbackBean;
    }
}

Dispatcher

实现Dispatcher接口,要求实现loadObject方法,返回期望的代理类。值的一提的是,loadobject方法在每次调用被拦截方法的时候都会被调用一次

/****
 * 与lazy不同的是,每一次调用代理方法的时候,都会调用一次Dispatcher的loadObject获取对象
 * 而lazy则会缓存下来。
 */
public class DispatcherCallBack implements Dispatcher {
    public Object loadObject() throws Exception {
        CallbackBean callbackBean = new CallbackBean();
        return callbackBean;
    }
}

Callback示例

package cglib.callback;

import org.springframework.cglib.proxy.Enhancer;

public class CallbackBean {

    private String name;
    private int value;

    public CallbackBean() {
        this.name = "tyrant";
        this.value = 123;
    }

    public Object add() {
        System.out.println("CallbackBean#add");
        return "1+1=2";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

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

}
package cglib.callback;

import org.springframework.cglib.proxy.Enhancer;

public class CallbackMultiTon {
    private String name;
    private int value;
    private PropertyBean propertyBean;
    public CallbackMultiTon(){
        this.name="tyrant";
        this.value=123;
        this.propertyBean=createPropertyBean();
    }
    protected PropertyBean createPropertyBean(){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(PropertyBean.class);
        enhancer.setCallback(new PropertyBeanDispatcherCallBack());
        System.out.println("---创建PropertyBean---");
        return (PropertyBean)enhancer.create();
    }

    public Object add(){
        System.out.println("CallbackBean#add");
        return "1+1=2";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

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

    public PropertyBean getPropertyBean() {
        return propertyBean;
    }

    public void setPropertyBean(PropertyBean propertyBean) {
        this.propertyBean = propertyBean;
    }
}

package cglib.callback;

import org.springframework.cglib.proxy.Enhancer;

public class CallbackSingleton {
    private String name;
    private int value;
    private PropertyBean propertyBean;
    public CallbackSingleton(){
        this.name="tyrant";
        this.value=123;
        this.propertyBean=createPropertyBean();
    }
    protected PropertyBean createPropertyBean(){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(PropertyBean.class);
        enhancer.setCallback(new PropertyBeanLazyLoader());
        System.out.println("---创建PropertyBean---");
        return (PropertyBean)enhancer.create();
    }

    public Object add(){
        System.out.println("CallbackBean#add");
        return "1+1=2";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

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

    public PropertyBean getPropertyBean() {
        return propertyBean;
    }

    public void setPropertyBean(PropertyBean propertyBean) {
        this.propertyBean = propertyBean;
    }
}

package cglib.callback;

import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.NoOp;

import java.lang.reflect.Method;

public class CallbackTest {
    public static void main(String[] args) {
        // NoOperate();
        // MethodInterceptorCallback();
        // LazyLoaderCallback();
        //DispatcherCallBack();
        // InvocationHandlerCallback();
        // FixValueCallback();
        //LazyLoaderCallbackPropertyBean();
        DispatcherCallbackPropertyBean();
    }

    public static void NoOperate() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CallbackBean.class);
        enhancer.setCallback(initCallBacks(0));
        CallbackBean callbackBean = (CallbackBean) enhancer.create();
        Object o = callbackBean.add();
        System.out.println("CallbackBean#add返回值:" + o.toString());
    }

    public static void MethodInterceptorCallback() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CallbackBean.class);
        enhancer.setCallback(initCallBacks(1));
        CallbackBean callbackBean = (CallbackBean) enhancer.create();
        Object o = callbackBean.add();
        System.out.println("CallbackBean#add返回值:" + o.toString());
    }

    public static void LazyLoaderCallback() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CallbackBean.class);
        enhancer.setCallback(initCallBacks(2));
        CallbackBean callbackBean = (CallbackBean) enhancer.create();
        callbackBean.getName();
        callbackBean.getName();

    }

    public static void DispatcherCallBack() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CallbackBean.class);
        enhancer.setCallback(initCallBacks(3));
        CallbackBean callbackBean = (CallbackBean) enhancer.create();
        //验证 cglib.callback.DispatcherCallBack.loadObject 会被调用多次
        callbackBean.getName();
        callbackBean.getName();
    }

    public static void InvocationHandlerCallback() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CallbackBean.class);
        enhancer.setCallback(initCallBacks(4));
        CallbackBean callbackBean = (CallbackBean) enhancer.create();
        Object o = callbackBean.add();
        System.out.println("CallbackBean#add返回值:" + o.toString());
    }

    public static void FixValueCallback() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CallbackBean.class);
        enhancer.setCallback(initCallBacks(5));
        CallbackBean callbackBean = (CallbackBean) enhancer.create();
        Object o = callbackBean.add();
        System.out.println("CallbackBean#add返回值:" + o.toString());
    }

    public static void LazyLoaderCallbackPropertyBean() {
        CallbackSingleton callbackPropertyBean = new CallbackSingleton();
        //验证 cglib.callback.LazyLoaderCallback.loadObject 只被调用1次
        //不调用callbackBean.getName();就不会加载
        callbackPropertyBean.getPropertyBean().getPropertyName();
        callbackPropertyBean.getPropertyBean().getPropertyName();

    }

    public static void DispatcherCallbackPropertyBean() {
        CallbackMultiTon callbackPropertyBean = new CallbackMultiTon();
        PropertyBean propertyBean = callbackPropertyBean.getPropertyBean();
        propertyBean.getPropertyName();
        propertyBean.getPropertyName();
    }


    /****
     * 初始化callback拦截器
     * @return
     */
    private static final Callback initCallBacks(Integer index) {
        NoOp instance = NoOp.INSTANCE;
        MethodInterceptorCallback methodInterceptorCallback = new MethodInterceptorCallback();
        LazyLoaderCallback lazyLoaderCallback = new LazyLoaderCallback();
        DispatcherCallBack dispatcherCallBack = new DispatcherCallBack();
        InvocationHandlerCallback invocationHandlerCallback = new InvocationHandlerCallback();
        FixValueCallback fixValueCallback = new FixValueCallback();
        Callback[] callbacks = new Callback[]{instance, methodInterceptorCallback, lazyLoaderCallback, dispatcherCallBack, invocationHandlerCallback, fixValueCallback};
        return callbacks[index];
    }

    /****
     * 初始化callback拦截数组
     * @return
     */
    private static final Callback[] initCallBacks() {
        NoOp instance = NoOp.INSTANCE;
        MethodInterceptorCallback methodInterceptorCallback = new MethodInterceptorCallback();
        LazyLoaderCallback lazyLoaderCallback = new LazyLoaderCallback();
        DispatcherCallBack dispatcherCallBack = new DispatcherCallBack();
        InvocationHandlerCallback invocationHandlerCallback = new InvocationHandlerCallback();
        FixValueCallback fixValueCallback = new FixValueCallback();
        Callback[] callbacks = new Callback[]{instance, methodInterceptorCallback, lazyLoaderCallback, dispatcherCallBack, invocationHandlerCallback, fixValueCallback};
        return callbacks;
    }

    /****
     * 初始化callback过滤器
     * @return
     */
    private static final CallbackFilter initCallbackFilter() {
        return new CallbackFilter() {
            @Override
            public int accept(Method method) {
                if (method.getName().equals("add")) {
                    //返回0 代表执行 callback数组里的下标为0的callback
                    return 0;
                }
                return 0;
            }
        };
    }
}

package cglib.callback;

import org.springframework.cglib.proxy.Dispatcher;
import org.springframework.cglib.proxy.FixedValue;

/****
 * 与lazy不同的是,每一次调用代理方法的时候,都会调用一次Dispatcher的loadObject获取对象
 * 而lazy则会缓存下来。即这个是多例
 */
public class DispatcherCallBack implements Dispatcher {
    @Override
    public Object loadObject() throws Exception {
        CallbackBean callbackBean = new CallbackBean();
        System.out.println("DispatcherCallBack#loadObject");
        return callbackBean;
    }
}


package cglib.callback;

import org.springframework.cglib.proxy.FixedValue;

/*****
 * 该callback相当于重写了相应的函数实现。并不会调用原函数
 */
public class FixValueCallback implements FixedValue {
    /*****
     * 被代理方法的指定函数将会无条件的返回改object,动态的变更返回值
     * @return
     * @throws Exception
     */
    @Override
    public Object loadObject() throws Exception {
        return "return FixValueCallback";
    }
}
package cglib.callback;


import org.springframework.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;

public class InvocationHandlerCallback implements InvocationHandler {
    /*****
     * invocationHandler的invoke方法传入的method和proxy都是代理本身对象
     * 切忌重复调用,会循环调用
     * @param proxy 代理类本身
     * @param method 代理类内部的方法
     * @param args  参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invocationHandlerCallback Before....");
        //InvocationHandler用的居然是直接创建1个父类的实例
        method.invoke(proxy.getClass().getSuperclass().newInstance(),args);
        //会无限循环
        //method.invoke(proxy,args);
        System.out.println("invocationHandlerCallback after....");
        return "return invocationHandlerCallback";
    }
}

package cglib.callback;

import org.springframework.cglib.proxy.LazyLoader;

/****
 *
 * 延迟加载初始化
 * 类似于spring prototype的singleton ,在第一次调用的时候进行初始化,并且将此实例存储起来,之后都将返回该实例
 * 可参考资料:
 * https://shensy.iteye.com/blog/1881277
 */
public class LazyLoaderCallback implements LazyLoader {
    @Override
    public Object loadObject() throws Exception {
        Object callbackBean = new CallbackBean();
        System.out.println("LazyLoaderCallback.loadObject");
        return callbackBean;
    }
}

package cglib.callback;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/****
 * 生成代理类字节码。对方法进行拦截调用
 */
public class MethodInterceptorCallback implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

        System.out.println("MethodInterceptor before invoke........");
        //MethodInterceptor用的是fastclass
        proxy.invokeSuper(obj,args);
        System.out.println("MethodInterceptor after invoke.........");
        return "return MethodInterceptor ";
    }
}

package cglib.callback;

public class PropertyBean {
    private String propertyName;  
    private int propertyValue;

    public String getPropertyName() {
        return propertyName;
    }

    public void setPropertyName(String propertyName) {
        this.propertyName = propertyName;
    }

    public int getPropertyValue() {
        return propertyValue;
    }

    public void setPropertyValue(int propertyValue) {
        this.propertyValue = propertyValue;
    }
}
package cglib.callback;

import org.springframework.cglib.proxy.Dispatcher;
import org.springframework.cglib.proxy.FixedValue;

/****
 * 与lazy不同的是,每一次调用代理方法的时候,都会调用一次Dispatcher的loadObject获取对象
 * 而lazy则会缓存下来。即这个是多例
 */
public class PropertyBeanDispatcherCallBack implements Dispatcher {
    @Override
    public Object loadObject() throws Exception {
        PropertyBean propertyBean = new PropertyBean();
        System.out.println("DispatcherCallBack#loadObject");
        return propertyBean;
    }
}