java代理的原理及應用

什麼是代理模式?

  定義

    爲其餘對象提供一種代理以控制對這個對象的訪問。在某些狀況下,一個對象不適合或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用。java

                                                                  ——百度百科spring

  代理模式的角色

  抽象角色:代理對象和真實對象的共同接口數組

  代理角色:代理對象角色內部含有對真實對象的引用,從而能夠操做真實對象,同時代理對象提供與真實對象相同的接口以便在任什麼時候刻都可以代替真實對象。同時,代理對象能夠在執行真實對象操做時,附加其餘的操做,至關於對真實對象進行封裝。ide

  真實角色:代理角色所表明的真實對象,是咱們最終要引用的對象。ui

  示意圖

    

代理模式的分類及使用

  • 靜態代理

1 package staticProxy;
2 
3 // 抽象角色,真是對象與代理對象的共同接口
4 public interface Subject {
5     public void request();
6 }
抽象角色
 1 package staticProxy;
 2 
 3 //代理對象,用來被客戶端直接調用的類,內部被注入真實對象,能夠在調用真是對象的方法先後作預處理和後處理
 4 public class ProxyClass implements Subject {
 5     
 6     Subject subject;
 7     
 8     ProxyClass (Subject subject) {
 9         this.subject = subject;
10     }
11 
12     @Override
13     public void request() {
14         System.out.println("prefix-process!");
15         subject.request();
16         System.out.println("suffix-process!");
17     }
18 
19 }
代理角色
 1 package staticProxy;
 2 
 3 //真實對象,委託類
 4 public class RealClass implements Subject {
 5 
 6     @Override
 7     public void request() {
 8         System.out.println("I'm realClass!");
 9     }
10 
11 }
真實角色
 1 package staticProxy;
 2 
 3 //客戶端
 4 public class StaticProxy {
 5     public static void main(String[] args) {
 6         Subject subject = new ProxyClass(new RealClass());
 7         
 8         subject.request();
 9     }
10 }
客戶端

    靜態代理的缺點很顯著,對每個委託類都須要建立一個代理類,爲了解決這個問題,java提供了動態代理。this

  • 動態代理

    抽象角色與真實角色的定義和靜態代理徹底一致,這裏再也不重複定義spa

    動態代理類須要繼承自InvocationHandler接口,並實現其中的invoke方法。代理

 1 package dynamicProxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 public class ProxyClass implements InvocationHandler {
 7 
 8     Object subject;
 9     
10     public ProxyClass(Object subject) {
11         this.subject = subject;
12     }
13     
14     @Override
15     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
16         System.out.println("prefix-process!");
17         method.invoke(subject, args);
18         System.out.println("suffix-process!");
19         return null;
20     }
21 
22 }
動態代理類
 1 package dynamicProxy;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 public class DynamicProxy {
 6     public static void main(String[] args) {
 7         
 8         Subject subject = (Subject) Proxy.newProxyInstance(RealClass.class.getClassLoader(),
 9                 new Class[] {Subject.class}, new ProxyClass(new RealClass()));
10         
11         subject.request();
12     }
13 }
客戶端

動態代理的實現原理

動態代理的實現主要依賴於java.lang.reflect.InvocationHandler接口與java.lang.reflect.Proxy類,其實現原理是基於java的反射技術。code

InvocationHandler接口

    動態代理類須要繼承自InvocationHandler接口,此接口中只包含一個方法invoke方法,接口原型以下:對象

 1 package java.lang.reflect;
 2 
 3 public interface InvocationHandler {
 4 
 5     /**
 6      * proxy:表明代理對象自己,用於調用本代理對象的其餘方法
 7      * method:表明正在被調用的委託類的方法
 8      * args:表明調用方法的參數
 9      */
10     public Object invoke(Object proxy, Method method, Object[] args)
11         throws Throwable;
12 }
InvocationHandler

Proxy類

    Proxy類中定義了不少的方法,但根據上面動態代理的應用咱們看到,最重要的一個方法就是newProxyInstance方法,該方法的做用就是動態建立一個代理類對象:

 1     /**
 2      * loader表明了委託類的類加載器
 3      * interfaces表明了委託類的接口數組
 4      * h表明委託類的實例
 5      */
 6     @CallerSensitive
 7     public static Object newProxyInstance(ClassLoader loader,
 8                                           Class<?>[] interfaces,
 9                                           InvocationHandler h)
10         throws IllegalArgumentException
11     {
12         // 判斷委託類實例是否爲空,若是未空拋異常
13         Objects.requireNonNull(h);
14 
15         final Class<?>[] intfs = interfaces.clone();
16         final SecurityManager sm = System.getSecurityManager();
17         if (sm != null) {
18             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
19         }
20 
21         /*
22          * 獲取獲取代理類的Class實例
23          */
24         Class<?> cl = getProxyClass0(loader, intfs);
25 
26         /*
27          * Invoke its constructor with the designated invocation handler.
28          */
29         try {
30             if (sm != null) {
31                 checkNewProxyPermission(Reflection.getCallerClass(), cl);
32             }
33 
34             //獲取代理類的Constructor對象
35             final Constructor<?> cons = cl.getConstructor(constructorParams);
36             final InvocationHandler ih = h;
37             if (!Modifier.isPublic(cl.getModifiers())) {
38                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
39                     public Void run() {
40                         cons.setAccessible(true);
41                         return null;
42                     }
43                 });
44             }
45 
46             //利用反射原理中使用constructor動態建立動態代理類型
47             return cons.newInstance(new Object[]{h});
48         } catch (IllegalAccessException|InstantiationException e) {
49             throw new InternalError(e.toString(), e);
50         } catch (InvocationTargetException e) {
51             Throwable t = e.getCause();
52             if (t instanceof RuntimeException) {
53                 throw (RuntimeException) t;
54             } else {
55                 throw new InternalError(t.toString(), t);
56             }
57         } catch (NoSuchMethodException e) {
58             throw new InternalError(e.toString(), e);
59         }
60     }
newProxyInstance

動態代理的應用場景

  動態代理最著名的應用場景就是spring中的aop

相關文章
相關標籤/搜索