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