Proxy Pattern 是一種結構模式,指爲其餘對象提供一種代理以控制對這個對象的訪問。java
代理模式通常包含三種角色: node
Subject:
定義的RealSubject和Proxy的共有方法,這個類能夠是接口,也能夠是抽象類。這樣全部使用RealSubject的地方均可以用Proxy代替。框架
RealSubject:
被代理類,此類定義了真實的Subject實現。ide
Proxy:
代理類通常要持有一個被代理的對象的引用,並可能負責建立和刪除被代理對象。性能
代理模式的實現大致上能夠分爲兩種,一種是靜態代理,一種是動態代理。兩種代理從JVM加載類的角度來說,本質上都是同樣的。this
上面的類圖就是傳統的靜態代理,代碼不貼了。(然而相關代碼接下來的demo裏有用到。)spa
優勢:.net
缺點:代理
JAVA的SDK中已經有了實現方法,Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);
使用JDK動態代理須要注意,目標類必須實現的某個接口,若是某個類沒有實現接口則不能生成代理對象。 code
優勢:
動態代理擴展性好。
缺點:
public static class SubjectInvocationHandler implements InvocationHandler { private Object object; public SubjectInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before 動態代理..."); System.out.println(proxy.getClass().getName()); System.out.println(this.object.getClass().getName()); return method.invoke(object, args); } } public static void main(String[] args) { Subject o = (Subject) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{Subject.class}, new SubjectInvocationHandler(new RealSubject())); o.request(); }
<dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.2</version> </dependency>
public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealSubject.class); enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> { System.out.println("before method run..."); Object result = proxy.invokeSuper(obj, args1); System.out.println("after method run..."); return result; }); RealSubject subject = (RealSubject) enhancer.create(); subject.request(); }
Cglib原理是針對目標類生成一個子類,覆蓋其中的全部方法,因此目標類和方法不能聲明爲final類型。
Cglib採用ASM框架寫Class字節碼,實現比JDK複雜,因此生產代理類比JDK動態代理效率低。
JDK是採用反射機制調用的,而CGLib經過FastClass機制直接調用方法,因此只需效率更高。
FastClass不使用反射類(Constructor或Method)來調用委託類方法,而是動態生成一個新的類(繼承FastClass),向類中寫入委託類實例直接調用方法的語句,用模板方式解決Java語法不支持問題,同時改善Java反射性能。
動態類爲委託類方法調用語句創建索引,使用者根據方法簽名(方法名+參數類型)獲得索引值,再經過索引值進入相應的方法調用語句,獲得調用結果。