前言
最近在了解spring aop的实现原理,了解到spring aop支持两种代理模式,jdk动态代理和cglib动态代理。
- jdk动态代理基于反射实现,通过反射创建一个实现代理接口的匿名类,在调用业务方法前调用InvocationHandler处理。代理类必须实现InvocationHandler接口,invoke方法是实现代理逻辑的地方,动态生成的代理类$Proxy0,继承了Proxy代理类,并实现了业务接口,由于java不允许多继承,所有jdk动态代理只能代理接口。
- cglib动态代理借助asm,通过字节码技术生成代理类,支撑类和接口的代理,具体原理见下篇。
案例
下面通过例子来说明jdk动态代理的应用和原理:
- 定义一个抽象主题接口Subject:
/**
* Subject
* 抽象主题接口
**/
public interface Subject {
void doSomething();
}
- 定义真实主题类RealSubject实现Subject:
/**
* RealSubject
* 真实主题类
*/
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something");
}
}
- 定义CustomerSubjectInvocationHandler实现InvocationHandler接口:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CustomerSubjectInvocationHandler implements InvocationHandler {
private Object target;
public CustomerSubjectInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before proxy do something...");
Object result = method.invoke(target, args);
System.out.println("after proxy do something...");
return result;
}
}
- 测试
import com.study.java.proxy.RealSubject;
import com.study.java.proxy.Subject;
import java.lang.reflect.Proxy;
/**
* JDKDynamicProxy
* jdk动态代理测试
*/
public class JDKDynamicProxy {
public static <T> T getProxy(Object o) {
return (T) Proxy.newProxyInstance(CustomerSubjectInvocationHandler.class.getClassLoader(), o.getClass().getInterfaces(), new CustomerSubjectInvocationHandler(o));
}
public static void main(String[] args) {
// 保存生成的代理类的字节码文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Subject subject = JDKDynamicProxy.getProxy(new RealSubject());
subject.doSomething();
}
}
运行后打印出结果:
before proxy do something...
RealSubject do something
after proxy do something...
成功实现代理。
通过添加
System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
打印动态生成的代理类:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.study.java.proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m3;
private static Method m2;
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});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void doSomething() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.study.java.proxy.Subject").getMethod("doSomething");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到$Proxy0就是动态生成的代理类,doSomething是被代理对象的发放,$Proxy0中调用了传入的InvocationHandler的invoke方法区代理执行业务方法,实现代理。$Proxy0继承了Proxy类,同时实现了Subject接口,由此可见为什么jdk动态代理只支持代理接口,因为java不允许多继承,动态代理类$Proxy0已经继承了Proxy类,无法再继承一个类了,只能implements实现多个接口
在上面的案例中可以发现,代理类是通过 Proxy.newProxyInstance获取的, Proxy.newProxyInstance有三个参数newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h),其中
ClassLoader loader:代理对象的类加载器
Class<?>[] interfaces:被代理的一组接口
InvocationHandler h:动态代理对象关联的InvocationHandler 实现类