與IoC相似的是,AOP也使用了一種設計模式,這種設計模式叫作代理模式。java
代理模式的做用是:爲其餘對象提供一種代理以控制對這個對象的訪問。設計模式
在某些狀況下,一個客戶不想或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用。數組
掌握代理模式對於Spring AOP的學習是相當重要的,甚至比Spring AOP自己的學習還要重要。ide
代理模式通常涉及到的角色有:函數
本身動手實現代理模式:post
抽象角色:Subject學習
package com.test.proxy; public abstract class Subject { public abstract void request(); }
真實角色:RealSubjectthis
package com.test.proxy; public class RealSubject extends Subject { @Override public void request() { System.out.println("from real subject"); } }
代理角色:ProxySubjectspa
package com.test.proxy; public class ProxySubject extends Subject { private RealSubject realSubject; @Override public void request() { this.preRequest(); if(null == realSubject) realSubject = new RealSubject(); realSubject.request(); this.postRequest(); } private void preRequest() { System.out.println("pre request"); } private void postRequest() { System.out.println("post request"); } }
客戶端:設計
package com.test.proxy; public class Client { public static void main(String[] args) { Subject subject = new ProxySubject(); subject.request(); } }
運行Client,輸出:
pre request from real subject post request
上面介紹的設計模式實際上叫作靜態代理,下面咱們介紹動態代理,它其實就是Spring AOP的底層實現。
動態代理類:
所謂Dynamic Proxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,而後該class就宣稱它實現了這些interface。你固然能夠把該class的實例看成這些interface中的任何一個來使用。固然這個Dynamic Proxy其實就是一個Proxy,他不會替你作實質性的工做,在生成它的實例時你必須提供一個handler,由它接管實際的工做。
Java動態代理類位於java.lang.reflect包下,通常主要涉及到如下兩個類:
下面咱們看下如何實如今程序中實現動態代理(在使用動態代理類時,咱們必須實現InvocationHandler接口):
被代理的類以及接口:
package com.test.dynamicproxy; public interface Subject { public void request(); } ---------------------------------------------------------------------------- package com.test.dynamicproxy; public class RealSubject implements Subject { public void request() { System.out.println("from real subject"); } }
代理類:
package com.test.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 該代理類的內部屬性是Object類型,實際使用的時候經過該類的構造方法傳遞進來一個對象 * 此外,該類還實現了invoke方法,該方法中的method.invoke其實就是調用被代理對象的將要 * 執行的方法,方法參數是sub,表示該方法從屬於sub,經過動態代理類,咱們能夠在執行真實對象的方法先後 * 加入本身的一些額外方法。 * */ public class ProxySubject implements InvocationHandler { private Object sub; public ProxySubject(Object object) { this.sub = object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("pre processing"); method.invoke(sub, args); System.out.println("post processing"); return null; } }
客戶端:
package com.test.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { // 模擬從Spring配置文件中獲得的subject RealSubject subject = new RealSubject(); InvocationHandler ih = new ProxySubject(subject); Class<?> clazz = subject.getClass(); // 一次性生成代理 Subject s = (Subject)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), ih); s.request(); // 由InvocationHandler的invock()方法執行真正的調用 } }
運行結果:
pre processing from real subject post processing
無論有多少具體的真實角色,代理能夠只有一個,這一個代理能夠用於處理全部的真實角色。
總結:動態代理的建立步驟(重要)
程序實踐:
package com.test.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.List; import java.util.Vector; public class VectorProxy implements InvocationHandler { private Object proxyobj; public VectorProxy(Object obj) { proxyobj = obj; } public static Object factory(Object obj) { Class<?> cls = obj.getClass(); return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new VectorProxy(obj)); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before calling " + method); if(args != null) for(int i = 0; i < args.length; i++) System.out.println(args[i]); Object object = method.invoke(proxyobj, args); return object; } public static void main(String[] args) { List v = (List)factory(new Vector()); v.add("hello"); v.add("world"); System.out.println(v); v.remove(0); System.out.println(v); } }
輸出:
before calling public abstract boolean java.util.List.add(java.lang.Object) hello before calling public abstract boolean java.util.List.add(java.lang.Object) world before calling public java.lang.String java.lang.Object.toString() [hello, world] before calling public abstract java.lang.Object java.util.List.remove(int) 0 before calling public java.lang.String java.lang.Object.toString() [world]
能夠看到與Vector操做相關的默認行爲已經發生了變化,這是因爲咱們施加了相關的代理。
程序實踐2:代理多個類的實例
package com.test.dynamicproxy; public interface Foo { void doAction(); } package com.test.dynamicproxy; public class FooImpl implements Foo { public FooImpl() { } public void doAction() { System.out.println("in FooImp1.doAction()"); } } package com.test.dynamicproxy; public class FooImpl2 implements Foo { public FooImpl2() { } public void doAction() { System.out.println("in FooImp2.doAction()"); } } package com.test.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class CommonInvocationHandler implements InvocationHandler { // 動態執行對象,須要回調的對象 private Object target; // 支持構造方法注射 public CommonInvocationHandler() { } // 支持構造方法注射 public CommonInvocationHandler(Object target) { setTarget(target); } /** * * 採用setter方法注射 * * @param target * */ public void setTarget(Object target) { this.target = target; } /** * * 調用proxy中指定的方法method,並傳入參數列表args * * @param proxy * 代理類的類型,例如定義對應method的代理接口 * * @param method * 被代理的方法 * * @param args * 調用被代理方法的參數 * * @return * * @throws java.lang.Throwable * */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); } } package com.test.dynamicproxy; import java.lang.reflect.Proxy; public class Demo { public static void main(String[] args) { // 1.通用的動態代理實現 CommonInvocationHandler handler = new CommonInvocationHandler(); Foo f; // 2.接口實現1 handler.setTarget(new FooImpl()); // 方法參數說明:代理類、代理類實現的接口列表、代理類的處理器 // 關聯代理類、代理類中接口方法、處理器,但代理類中接口方法被調用時,會自動分發處處理器的invoke方法 // 若是代理類沒有實現指定接口列表,會拋出非法參數異常 f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler); f.doAction(); // 3.接口實現2 handler.setTarget(new FooImpl2()); f.doAction(); } }