代理一般有靜態代理,動態代理,其中靜態代理是經過持有目標對象引用,而後對目標對象的方法進行加強,能夠說是一種硬編碼。jdk動態代理也須要持有目標對象的引用,在目標對象的方法的調用處進行加強,但這部分被封在處理器InvocationHandler中,經過反射機制生成Proxy實例,並傳入處理器。----先來看下使用jdk動態代理實現方式:java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object object){
this.target = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before......");
Object result = method.invoke(target,args);
System.out.println("after......");
return result;
}
@SuppressWarnings("unchecked")
public <T> T getProxy(){
return (T)Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
}
動態是相對於靜態代理而言,jvm執行java類,須要先將class文件加載到jvm中,java是不容許在運行時修改class文件的,因此要想使用動態代理,須要動態生成class文件,加載到jvm中。經過設置系統屬性,能夠在運行時看到jdk動態生成的class文件。spring
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");在生成的類文件中,能夠看到代理類繼承自Proxy並實現了業務自定義的接口,下面是動態生成的代理類部分代碼:
public final class $Proxy0 extends Proxy implements IHello{能夠看到jdk動態代理生成的代碼,將目標對象接口的全部方法進行了代理,目標方法的執行就變成了處理器的invoke,在invoke中已經對目標對象中進行了加強。
public final String hello(String var1) throws {
return (String)super.h.invoke(this, m3, new Object[]{var1});
}
static {
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.proxy.IHello").getMethod("hello", Class.forName("java.lang.String"));
}
}
由ProxyClassFactory在給定類加載器和接口數組的條件下,生成、定義、並返回代理class。
設計模式
最後將class字節碼加載到jvm,在生成代理類的函數中能夠看到是否生成class文件的布爾標記saveGeneratedFiles:數組
jdk動態代理無處不在,大名鼎鼎的spring AOP默認使用的就是jdk動態代理,對於沒有接口實現的類才使用cglib代理。jvm