代理模式與它在原始碼中的運用
代理是指一個包裝了真實訪問物件的類,以便控制對真實類的訪問

訪問流程如下

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); } } ... } 複製程式碼
使用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的情況
- 虛代理:根據需要建立開銷很大的物件,只有用到時才建立
- 保護代理:控制對原始物件的訪問
- 智慧指引:在訪問物件時附加了一些操作,比如物件沒有引用時釋放它
- 遠端代理:為一個物件在不同的地址空間提供區域性代表