java動態代理的實現及原理, 混型應用

在java的動態代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另外一個則是 Proxy(Class),這一個類和接口是實現咱們動態代理所必須用到的。java

示例:數組

public class DynamicProxyTest {

    interface UserService {  
        public abstract void add();  
    }  

    interface UserService2 {  
        public abstract void add2();  
    }  


    static class UserServiceImpl implements UserService, UserService2 {  

        public void add() {  
            System.out.println("----- add -----");  
        }

        public void add2() {
            System.out.println("----- add 2-----");  
        }  
    } 


    static class MyInvocationHandler implements InvocationHandler {  

        private Object target;  

        public MyInvocationHandler(Object target) {  
            super();  
            this.target = target;  
        }  

        public Object getProxy() {  
        /** * Thread.currentThread().getContextClassLoader(:  一個ClassLoader對象,定義了由哪一個ClassLoader對象來對生成的代理對象進行加載 * arget.getClass().getInterfaces():  一個Interface對象的數組,表示的是我將要給我須要代理的對象提供一組什麼接口,若是我提供了一組接口給它,那麼這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了 * this:  一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪個InvocationHandler對象上 */
            return Proxy.newProxyInstance(Thread.currentThread()  
                    .getContextClassLoader(), target.getClass().getInterfaces(),  
                    this);  
        }  

        /** * proxy:  咱們所代理的那個真實對象 * method:  咱們所要調用真實對象的某個方法的Method對象 * args:  調用真實對象某個方法時接受的參數 */
        public Object invoke(Object proxy, Method method, Object[] args)  
                throws Throwable {  
            System.out.println("----- before -----");  
            Object result = method.invoke(target, args);  
            System.out.println("----- after -----");  
            return result;  
        }
    }  

    /** * @param args */
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();  
        MyInvocationHandler invocationHandler = new MyInvocationHandler(  
                userService);  

        UserService proxy = (UserService) invocationHandler.getProxy();  
        proxy.add();
        ((UserService2)proxy).add2();
    }

}

執行結果:markdown

----- before -----
----- add -----
----- after -----
----- before -----
----- add 2-----
----- after -----

代理實現過程當中的問題說明:
1. 這個代理對象是由誰且怎麼生成的?函數

Proxy.newProxyInstance方法的實現裏會經過建立一個代理類,並返代理實例供咱們使用
  1. invoke方法是怎麼調用的?

咱們拿的的代理類是在編譯過程當中有jdk自動生成的. 類裏會實現各個接口的方法,實現的方法裏會調用invoke,例如:this

public final void add()  
    throws   
  {  
    try  
    {  
      this.h.invoke(this, m3, null);  
      return;  
    }  
    catch (Error|RuntimeException localError)  
    {  
      throw localError;  
    }  
    catch (Throwable localThrowable)  
    {  
      throw new UndeclaredThrowableException(localThrowable);  
    }  
  }
  1. invoke和add方法有什麼對應關係?

實現InvocationHandler 這個接口的實例會有invoke方法,而且會執行spa

Object result = method.invoke(target, args);

經過獲得執行後的返回值,add方法就在此時被真正的實例調用add方法代理

  1. 生成的代理對象是什麼樣子的?

編譯成功後能夠去$Proxy0.class文件查看內容code

總結:
一個典型的動態代理建立對象過程可分爲如下四個步驟:
一、經過實現InvocationHandler接口建立本身的調用處理器 IvocationHandler handler = new InvocationHandlerImpl(…);
二、經過爲Proxy類指定ClassLoader對象和一組interface建立動態代理類
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
三、經過反射機制獲取動態代理類的構造函數,其參數類型是調用處理器接口類型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
四、經過構造函數建立代理類實例,此時需將調用處理器對象做爲參數被傳入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
爲了簡化對象建立過程,Proxy類中的newInstance方法封裝了2~4,只需兩步便可完成代理對象的建立。
生成的ProxySubject繼承Proxy類實現Subject接口,實現的Subject的方法實際調用處理器的invoke方法,而invoke方法利用反射調用的是被代理對象的的方法(Object result=method.invoke(proxied,args))對象

動態代理與混型的應用繼承

示例代碼:

public class DynamicProxyMixin {

    class TwoTuple<A, B> {

        public A first;
        public B second;

        public TwoTuple(A a, B b) {
            this.first = a;
            this.second = b;
        }
    }
    interface TimeStamped {
        long getStamped();
    }

    static class TimeStampedImpl implements TimeStamped {
        private final long date;

        public TimeStampedImpl() {
            date = new Date().getTime();
        }

        public long getStamped() {
            return date;
        }
    }

    interface SerialNumbered {
        long getSerialNumbered();
    }

    static class SerialNumberedImpl implements SerialNumbered {
        private static long counter = 1;
        private final long serialNumber = counter++;
        public long getSerialNumbered() {
            return serialNumber;
        }
    }

    interface Basic {
        void set(String val);
        String get();
    }

    static class BasicImpl implements Basic {
        private String value;
        public void set(String val) {
            value = val;
        }
        public String get() {
            // TODO Auto-generated method stub
            return value;
        }
    }

    static class MixinProxy implements InvocationHandler {
        Map<String, Object> delegateByMethodMap;

        private MixinProxy(TwoTuple<Object, Class<?>> ...pairs) {
            delegateByMethodMap = new HashMap<String, Object>();
            for (TwoTuple<Object, Class<?>> pair : pairs) {
                for (Method method : pair.second.getMethods()) {
                    String methodName = method.getName();
                    if (!delegateByMethodMap.containsKey(methodName)) {
                        delegateByMethodMap.put(methodName, pair.first);
                    }
                }
            }
        }

        public Object invoke(Object proxy, Method method, Object[] arg2)
                throws Throwable {
            String methodName = method.getName();
            return method.invoke(delegateByMethodMap.get(methodName), arg2);
        }

        public static Object newInstance(TwoTuple<Object, Class<?>> ...pairs){
            Class[] interfaces = new Class[pairs.length];

            for (int i = 0, count = interfaces.length; i < count; i++) {
                interfaces[i] = (Class) pairs[i].second;
            }
            ClassLoader loader = pairs[0].first.getClass().getClassLoader();
            return Proxy.newProxyInstance(loader, interfaces, new MixinProxy(pairs));
        }
    }


    /** * @param args */
    public static void main(String[] args) {
        Object proxyObject = MixinProxy.newInstance(new TwoTuple(new BasicImpl(), Basic.class),
                new TwoTuple(new TimeStampedImpl(), TimeStamped.class),
                new TwoTuple(new SerialNumberedImpl(), SerialNumbered.class));

        Basic b = (Basic) proxyObject;
        SerialNumbered serialNumbered = (SerialNumbered) proxyObject;
        TimeStamped timeStamped = (TimeStamped) proxyObject;
        b.set("hello");
        System.out.println(b.get());
        System.out.println(serialNumbered.getSerialNumbered());
        System.out.println(timeStamped.getStamped());
    }
}

執行結果:

hello
1
1494841280897

經過動態代理獲得的proxyObject實例就是一個混型類型,擁有多個接口功能.

相關文章
相關標籤/搜索