4.CGLIB动态代理代码示例


highlight: arduino-light

实现动态代理的几种方案

  • 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代理示例代码

java 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; } }

```java 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;
}

} ```

```java 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.DEBUGLOCATIONPROPERTY, "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接口,此接口源码如下:

java 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

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

```java package org.springframework.cglib.proxy;

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

FixedValue

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

```java 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方法。切忌不要造成循环调用

```java 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.

```java 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类初始化时进行了成员的赋值,之后使用该成员进行调用父类方法

```java 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方法在每次调用被拦截方法的时候都会被调用一次

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

Callback示例

```java 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;
}

} ```

```java 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;
}

}

```

```java 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;
}

}

```

```java 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;
        }
    };
}

}

```

```java 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; } }

```

```java 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"; } } ```

```java 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"; } }

```

```java 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; } }

```

```java 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 ";
}

}

```

```java 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;
}

} ```

```java 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; } } ```

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值