? 簡單的說,代理模式是在目標對象和訪問對象之間增加了一層代理對象,所有的訪問對象通過代理對象來實現對目標對象的調用。
????????代理對象和目標對象實現同一個接口,由代理對象來調用目標對象,對于外部來說,代理對象就可以替代目標對象被調用。通過這種方式,代理對象中可以在正常的訪問中增加額外的邏輯,比如緩存、權限控制、日志記錄等。
????????但是這種靜態代理的模式需要增加額外的代理類的實現,Java 5開始引入了動態代理機制,實現了在運行時動態地創建出代理對象,這其實是一種方法調用的攔截,AOP就是利用了這種模式。
?
動態代理的使用例子?
1 | <span style= "font-size:16px;" > package ?com.dynamic.jdk;<br><br> /**<br> * 目標類的接口定義<br> * <p/><br> * Created by Vincent Tse on 12/2/15.<br> */ <br> public ?interface ?MyInterface {<br> ? ? void ?doSomething();<br>}<br></span> |
1 | <span style= "font-size:16px;" > package ?com.dynamic.jdk;<br><br> /**<br> * 目標類的具體實現<br> * <p/><br> * Created by Vincent Tse on 12/2/15.<br> */ <br> public ?class ?MyInterfaceImpl? implements ?MyInterface {<br><br> ? ? @Override <br> ? ? public ?void ?doSomething() {<br> ? ? ? ?System.out.println( "here is my real operation!" );<br> ? ?}<br>}<br></span> |
1 | <span style= "font-size:16px;" > package ?com.dynamic.jdk;<br><br> import ?java.lang.reflect.InvocationHandler;<br> import ?java.lang.reflect.Method;<br><br> /**<br> * 自定義的InvocationHandler<br> * 封裝具體的調用過程<br> * <p/><br> * Created by Vincent Tse on 12/2/15.<br> */ <br> public ?class ?MyInvocationHandler? implements ?InvocationHandler {<br> ? ? //target是真正執行方法的目標對象<br> ? ?private Object target;<br><br> ? ?public MyInvocationHandler(Object target) {<br> ? ? ? ?super();<br> ? ? ? ?this.target = target;<br> ? ?}<br><br> ? ?/**<br> ? ? * 代理對象調用的方法<br> ? ? * @param proxy<br> ? ? * @param method<br> ? ? * @param args<br> ? ? * @return<br> ? ? * @throws Throwable<br> ? ? */<br> ? ?@Override<br> ? ?public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {<br> ? ? ? ?System.out.println("before target's operation!");<br> ? ? ? ?Object result = method.invoke(target, args);<br> ? ? ? ?System.out.println("after target's operation");<br> ? ? ? ?return result;<br> ? ?}<br>}<br></span> |
1 | <span style= "font-size:16px;" > package ?com.dynamic.jdk;<br><br> import ?java.lang.reflect.Proxy;<br><br> /**<br> * 測試類<br> * <p/><br> * Created by Vincent on 12/2/15.<br> */ <br> public ?class ?DynamicTest {<br><br> ? ? public ?static ?void ?main(String[] args) {<br><br> ? ? ? ? //生成目標對象<br> ? ? ? ?MyInterface myInterface = new MyInterfaceImpl();<br><br> ? ? ? ?//實例化invocationHandler對象,傳入目標對象作為target<br> ? ? ? ?MyInvocationHandler invocationHandler = new MyInvocationHandler(myInterface);<br><br> ? ? ? ?//調用Proxy的方法生成代理對象<br> ? ? ? ?MyInterface proxy = (MyInterface)Proxy.newProxyInstance(myInterface.getClass().getClassLoader(),<br> ? ? ? ? ? ? ? ?new Class[]{MyInterface.class}, invocationHandler);<br><br> ? ? ? ?//調用代理對象的方法<br> ? ? ? ?proxy.doSomething();<br> ? ?}<br>}<br></span> |
輸出結果:
before?target's?operation!
here?is?my?real?operation!
after?target's?operation!?
?
使用起來很簡單,接下來看源碼分析其中的原理
從Proxy的newProxyInstance()方法開始,這個方法就是用來生成代理對象的,需要傳入類加載器、實現的接口以及一個InvocationHandler對象。?
1 | <span style= "font-size:16px;" > public ?static ?Object newProxyInstance(ClassLoader loader,<br> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Class<?>[] interfaces,<br> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?InvocationHandler h)<br> ? ? throws ?IllegalArgumentException<br>{<br> ? ?Objects.requireNonNull(h);<br><br> ? ? final ?Class<?>[] intfs = interfaces.clone();<br> ? ? final ?SecurityManager sm = System.getSecurityManager();<br> ? ? if ?(sm !=? null ) {<br> ? ? ? ?checkProxyAccess(Reflection.getCallerClass(), loader, intfs);<br> ? ?}<br><br> ? ? //通過傳入的類加載器和實現接口生成代理類<br> ? ?Class<?> cl = getProxyClass0(loader, intfs);<br><br> ? ?/*<br> ? ? * Invoke its constructor with the designated invocation handler.<br> ? ? */<br> ? ?try {<br> ? ? ? ?if (sm != null) {<br> ? ? ? ? ? ?checkNewProxyPermission(Reflection.getCallerClass(), cl);<br> ? ? ? ?}<br> ? ? ? ? ? ? ? ? ?//反射獲取代理類的構造函數<br> ? ? ? ?final Constructor<?> cons = cl.getConstructor(constructorParams);<br> ? ? ? ?final InvocationHandler ih = h;<br> ? ? ? ?if (!Modifier.isPublic(cl.getModifiers())) {<br> ? ? ? ? ? ?AccessController.doPrivileged(new PrivilegedAction<Void>() {<br> ? ? ? ? ? ? ? ?public Void run() {<br> ? ? ? ? ? ? ? ? ? ?cons.setAccessible(true);<br> ? ? ? ? ? ? ? ? ? ?return null;<br> ? ? ? ? ? ? ? ?}<br> ? ? ? ? ? ?});<br> ? ? ? ?}<br> ? ? ? ?//反射生成實例,將invocationHandler傳入,之后調用invoke方法就靠它了<br> ? ? ? ?return cons.newInstance(new Object[]{h});<br> ? ?} catch (IllegalAccessException|InstantiationException e) {<br> ? ? ? ?throw new InternalError(e.toString(), e);<br> ? ?} catch (InvocationTargetException e) {<br> ? ? ? ?Throwable t = e.getCause();<br> ? ? ? ?if (t instanceof RuntimeException) {<br> ? ? ? ? ? ?throw (RuntimeException) t;<br> ? ? ? ?} else {<br> ? ? ? ? ? ?throw new InternalError(t.toString(), t);<br> ? ? ? ?}<br> ? ?} catch (NoSuchMethodException e) {<br> ? ? ? ?throw new InternalError(e.toString(), e);<br> ? ?}<br>} <br></span> |
?
?
getProxyClass0()方法就是用來生成代理類的,首先檢查實現接口數量,大于65535就拋異常,記得以前java培訓的時候老師講過這塊,感覺應該不會有實現那么多接口的類吧。
1 | <span style= "font-size:16px;" > private ?static ?Class<?> getProxyClass0(ClassLoader loader,<br> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Class<?>... interfaces) {<br> ? ? if ?(interfaces.length >? 65535 ) {<br> ? ? ? ? throw ?new ?IllegalArgumentException( "interface limit exceeded" );<br> ? ?}<br><br> ? ? ?? //從一個Cache中獲取代理類,如果沒有就重新生成<br> ? ?return proxyClassCache.get(loader, interfaces);<br>}<br></span> |
?
proxyClassCache是一個靜態的WeakCache,定義在Proxy類里。
WeakCache里有兩個factory,一個是subKeyFactory,?是一個映射函數(key, parameter)->sub-key, 另一個是valueFactory,是一個映射函數(key,?parameter)->value。WeakCache的get方法需要兩個參數,一個是key,另一個是parameter。
具體WeakCache的用法與原理這里不再贅述,請參考源碼。
1 | <span style= "font-size:16px;" > private ?static ?final ?WeakCache<ClassLoader, Class<?>[], Class<?>><br> ? ?proxyClassCache =? new ?WeakCache<>( new ?KeyFactory(),? new ?ProxyClassFactory());<br></span> |
這里傳入的KeyFactory和ProxyClassFactory是Proxy類中定義的靜態類,分別對應了WeakCache中的subKeyFactory和valueFactory,都實現了BiFunction接口,并實現了apply()方法。ProxyClassFactory的apply()方法里完成的就是生成代理類的邏輯,最關鍵的是
1 | <span style= "font-size:16px;" > byte [] proxyClassFile = ProxyGenerator.generateProxyClass(<br> ? ?proxyName, interfaces, accessFlags);<br></span> |
上面的方法用來生成代理類的字節碼,這個代理類里會有接口的實現方法,在實現的方法中會調用InvocationHandler的invoke()方法,有興趣的可以將生成的字節碼寫到本地,用反編譯工具打開看一下。
?
那么ProxyClassFactory的apply()方法是在什么時候被調用的呢,回到WeakCache的get()方法
1 | <span style= "font-size:16px;" > //生成subkey來獲取對應的supplier<br>Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));<br>Supplier<V> supplier = valuesMap.get(subKey);<br>Factory factory = null;<br>//一直循環,直到從supplier中獲取到value為止<br>//如果沒有supplier就生成factory并加入到緩存中(源碼說這是一個install的過程)<br>while (true) {<br> ? ?if (supplier != null) {<br> ? ? ? ?V value = supplier.get();<br> ? ? ? ?if (value != null) {<br> ? ? ? ? ? ?return value;<br> ? ? ? ?}<br> ? ?}<br> ? ?<br> ? ?if (factory == null) {<br> ? ? ? ?//Factory是內部類,實現了Supplier接口,實現了get()方法<br> ? ? ? ?//實際上在get()方法中調用了valueFactory(也就是ProxyClassFactory)的apply()方法<br> ? ? ? ?//可以debug進去看<br> ? ? ? ?factory = new Factory(key, parameter, subKey, valuesMap);<br> ? ?}<br><br> ? ?if (supplier == null) {<br> ? ? ? ?supplier = valuesMap.putIfAbsent(subKey, factory);<br> ? ? ? ?if (supplier == null) {<br> ? ? ? ? ? ?supplier = factory;<br> ? ? ? ?}<br> ? ?} else {<br> ? ? ? ?if (valuesMap.replace(subKey, supplier, factory)) {<br> ? ? ? ? ? ?supplier = factory;<br> ? ? ? ?} else {<br> ? ? ? ? ? ?supplier = valuesMap.get(subKey);<br> ? ? ? ?}<br> ? ?}<br>}<br></span> |
好辛苦,終于生成代理類了,回到newProxyInstance方法,有了代理類的Class對象,就可以通過反射生成實例(調用的是帶InvocationHandler參數的構造函數),生成實例之后就可以用代理對象了。