实现动态代理的几种方案
- 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;
}
}