在Java中,许多框架的底层都是基于动态代理来实现的,比如Aop,mybaits动态生成数据库操作类。在Java中有两种动态代理的方法,一种是JDK原生的动态代理,一种是基于Cglib的代理方式
为其他对象提供一种代理以控制对这个对象的访问
与静态代理在程序运行前就已经存在的方式不同,动态代理指的是代理类是在运行时才被创建出来的。相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
1.定义接口
/*
* @Author Avalon
* @Email [email protected]
* @Version V1.0
* @Created Date:2017/8/6
*/
public interface IService {
String doService(String s);
}
2.定义实现类
/*
* @Author Avalon
* @Email [email protected]
* @Version V1.0
* @Created Date:2017/8/6
*/
public class ServiceImpl implements IService {
@Override
public String doService(String s) {
return String.format("hello:%s", s);
}
}
3.InvocationHandler类
/*
*
* @Author Avalon
* @Email [email protected]
* @Version V1.0
* @Created Date:2017/8/6
*/
public class MyInvocationHandler<T> implements InvocationHandler {
private T target;
public MyInvocationHandler(T target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用前");
Object result = method.invoke(target, args);
System.out.println("方法调用后");
return result;
}
public T getProxy() {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
}
}
4.测试类
/*
*
* @Author Avalon
* @Email [email protected]
* @Version V1.0
* @Created Date:2017/8/6
*/
public class MyInvocationHandler<T> implements InvocationHandler {
private T target;
public MyInvocationHandler(T target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用前");
Object result = method.invoke(target, args);
System.out.println("方法调用后");
return result;
}
public T getProxy() {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
}
}
运行结果
方法调用前
hello:Avalon
方法调用后
可以看到在方法动用前后都打印出了相应的日志,说明方法已经成功被代理了。那具体JDK是怎么实现的呢,让我们来看看JDK生成的代理类$Proxy0
public final class $Proxy0 extends Proxy implements IService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void doService(String var1) throws {
try {
//将被代理的方法method,参数,及代理类传给invokeHandler调用
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("IService").getMethod("doService", new Class[]{Class.forName("java.lang.String")});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
也就是说main函数里面的proxy实际就是$Proxy0的一个实例对象。可知JDK动态代理是使用接口生成新的实现类,实现类里面则委托给InvocationHandler,InvocationHandler里面则调用被代理的类方法。
Cglib(Code Generation Library)。是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。它不需要被代理的类实现某个接口就可以实现动态代理
1.Service类
public class ServiceImpl {
public void doService(String s) {
System.out.println(String.format("hello:%s", s));
}
}
2.CglibProxy代理
public class CglibProxy implements MethodInterceptor {
@Override
//Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。
public Object intercept(Object obj, Method method, Object[] params, MethodProxy proxy) throws Throwable {
System.out.println("调用前");
Object result = proxy.invokeSuper(obj, params);
System.out.println(" 调用后");
return result;
}
//Enhancer类是CGLib中的一个字节码增强器
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
}
3.测试类
public class Test {
public static void main(String[] args) {
//生成代理类到本地
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "target/cglib");
ServiceImpl service = new ServiceImpl();
CglibProxy cp = new CglibProxy();
ServiceImpl proxy = (ServiceImpl) cp.getProxy(service.getClass());
proxy.doService("avalon");
}
}
生成代理类反编译后:
public class ServiceImpl$$EnhancerByCGLIB$$2c41332b extends ServiceImpl 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$doService$0$Method;
private static final MethodProxy CGLIB$doService$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("ServiceImpl$$EnhancerByCGLIB$$2c41332b");
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$doService$0$Method = ReflectUtils.findMethods(new String[]{"doService", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("ServiceImpl")).getDeclaredMethods())[0];
CGLIB$doService$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "doService", "CGLIB$doService$0");
}
final String CGLIB$doService$0(String var1) {
return super.doService(var1);
}
public final String doService(String var1) {
//方法拦截器
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
//将具体方法调用方在拦截器中执行
return var10000 != null?(String)var10000.intercept(this, CGLIB$doService$0$Method, new Object[]{var1}, CGLIB$doService$0$Proxy):super.doService(var1);
}
//其他
....
}
从代理类里面可知道对于原来的doService函数,代理类里面对应了两个函数分布是doService 和CGLIB$doService 0 其 中 后 者 是 在 方 法 拦 截 器 里 面 调 用 的 的 , 前 者 则 是 我 们 使 用 代 理 类 时 候 调 用 的 函 数 。 当 我 们 代 码 调 用 d o S e r v i c e 时 候 , 会 具 体 调 用 到 方 法 拦 截 器 的 i n t e r c e p t 方 法 , 该 方 法 内 则 通 过 p r o x y . i n v o k e S u p e r 调 用 C G L I B 0 其中后者是在方法拦截器里面调用的的,前者则是我们使用代理类时候调用的函数。当我们代码调用doService时候,会具体调用到方法拦截器的intercept方法,该方法内则通过proxy.invokeSuper调用CGLIB 0其中后者是在方法拦截器里面调用的的,前者则是我们使用代理类时候调用的函数。当我们代码调用doService时候,会具体调用到方法拦截器的intercept方法,该方法内则通过proxy.invokeSuper调用CGLIBdoService$0