代理模式與它在原始碼中的運用

爬蜥發表於2019-01-27

代理是指一個包裝了真實訪問物件的類,以便控制對真實類的訪問

代理模式與它在原始碼中的運用

訪問流程如下

代理模式與它在原始碼中的運用
public interface SubjectInterface { 
void hi();

}public class RealSubject implements SubjectInterface {
@Override public void hi() {
System.out.print("hi");

}
}public class SubjectProxy implements SubjectInterface{
private RealSubject r;
public SubjectProxy() {
r=new RealSubject();

} @Override public void hi() {
System.out.println("proxy");
r.hi();

}
}public class Client {
public static void main(String[] args) {
SubjectInterface subject = new SubjectProxy();
subject.hi();

}
}複製程式碼

此時RealSubject作為代理物件的一個屬性欄位,在執行之前就會生成RealSubject的位元組碼檔案,這種方式也稱作靜態代理

動態代理

被代理的類在執行時動態生成的,編譯的時候並沒有生成RealSubject

使用JDK實現動態代理

jdk實現動態代理必須有實現介面InvocationHandler的處理類,用於執行被代理類的方法

public class SubjectInvocationHandler implements InvocationHandler { 
private Object myproxy;
public SubjectInvocationHandler(Object proxy) {
this.myproxy = proxy;

} @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invocation handler");
method.invoke(myproxy,args);
return null;

}
}複製程式碼

客戶端通過使用java.lang.reflect.Proxy自行建立代理,然後呼叫目標方法即可

public class Client { 
public static void main(String[] args) {
//classloader會被用來驗證是否可以載入傳入的介面, SubjectInterface proxy = (SubjectInterface) Proxy.newProxyInstance(SubjectInterface.class.getClassLoader() , new Class[]{SubjectInterface.class
} , new SubjectInvocationHandler(new RealSubject()));
proxy.hi();

}複製程式碼

訪問流程如下

代理模式與它在原始碼中的運用

生成代理proxy class階段

代理物件會在內部快取,如果沒有快取則會由ProxyClassFactory新生成。
首先會做介面校驗,比如是否可以從提供的classLoader獲取介面

    Class<
?>
interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);

} catch (ClassNotFoundException e) {

} if (interfaceClass != intf) {
throw new IllegalArgumentException( intf + " is not visible from class loader");

}複製程式碼

驗證完畢後,會讀取介面的class檔案使用的是 ProxyGenerator.generateProxyClass,可以看到它會對整個的class檔案的位元組做讀取

private byte[] generateClassFile() { 
... dout.writeInt(0xCAFEBABE);
...
}複製程式碼

最後呼叫native方法生成代理物件,並存入快取

獲取proxy的建構函式

建構函式指定的引數就是InvocationHandler

建立例項

呼叫建構函式,傳入自定義的invocationHandler,自此生成了一個proxy例項,且例項本身會實現傳入的介面,程式碼例項生成的物件如下所示

public final class $Proxy0 extends Proxy implements SubjectInterface { 
... public final void hi() throws {
try {
//這裡的h即Proxy中的InvocationHandler,也就是使用者自定義的InvocationHanlder //這個this物件代表的也就是 $Proxy0 本身 super.h.invoke(this, m3, (Object[])null);

} catch (RuntimeException | Error var2) {
throw var2;

} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);

}
} ...
}複製程式碼

從JVM dump下動態代理的類

使用CGlib動態代理

引入CGlib之後,執行如下程式碼即可

public class Client { 
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new MethodInterceptor() {
@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib:"+method.getName());
methodProxy.invokeSuper(o, objects);
return o;

}
});
RealSubject realSubject = (RealSubject)enhancer.create();
realSubject.hi();

}
}複製程式碼

動態代理在spring aop中的運用

spring中預設使用DefaultAopProxyFactory

 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<
?>
targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation.");

} if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//對於介面使用的是JDK return new JdkDynamicAopProxy(config);

} //其餘使用Cglib作為動態代理的實現 return new ObjenesisCglibAopProxy(config);

} else {
return new JdkDynamicAopProxy(config);

}
}複製程式碼

JdkDynamicAopProxy

它實現了InvocationHandler和AopProxy。AopProxy主要是負責提供getProxy,實現為

@Override public Object getProxy() { 
return getProxy(ClassUtils.getDefaultClassLoader());

} @Override public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());

} Class<
?>
[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

}複製程式碼

當有需要執行的方法的時候,則是執行invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
... invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed();
...
}public Object proceed() throws Throwable {
... if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
//這裡會執行AfterReturningAdviceInterceptor、AspectJAfterThrowingAdvice等等方法 return dm.interceptor.invoke(this);

} ...
}複製程式碼

CglibAopProxy

它實現了AopProxy,核心的生成代理的方式如下

public Object getProxy(@Nullable ClassLoader classLoader) { 
... Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &
&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);

}
} enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<
?>
[] types = new Class<
?>
[callbacks.length];
for (int x = 0;
x <
types.length;
x++) {
types[x] = callbacks[x].getClass();

} // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks);
...
}private Callback[] getCallbacks(Class<
?>
rootClass) throws Exception {...Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
...Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice targetInterceptor, // invoke target without considering advice, if optimized new SerializableNoOp(), // no override for methods mapped to this targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised)
};
...else {
callbacks = mainCallbacks;

}...
}複製程式碼

以DynamicAdvisedInterceptor為例,它就實現了MethodInterceptor

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 
... //同樣在此處去執行具體的Advice retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
...
}複製程式碼

通常可以使用Proxy的情況

  1. 虛代理:根據需要建立開銷很大的物件,只有用到時才建立
  2. 保護代理:控制對原始物件的訪問
  3. 智慧指引:在訪問物件時附加了一些操作,比如物件沒有引用時釋放它
  4. 遠端代理:為一個物件在不同的地址空間提供區域性代表

來源:https://juejin.im/post/5c4d3f28f265da6142743f9e

相關文章