三、Java高級特性(註解、反射、動態代理)

一、靜態代理

實現代碼:
(1)自定義接口HttpRequest

package com.it.test.proxy;

/**
 * http 請求的接口
 */
public interface HttpRequest {
    void get();
    void post();

}

(2)創建實現類Retrofit、Vally。並實現HttpRequest接口

package com.it.test.proxy;

public class Retrofit implements HttpRequest {
    @Override
    public void get() {
        System.out.println("Retrofit get");
    }

    @Override
    public void post() {
        System.out.println("Retrofit post");
    }
}

package com.it.test.proxy;

public class Vally implements HttpRequest {
    @Override
    public void get() {
        System.out.println("Vally get");
    }

    @Override
    public void post() {
        System.out.println("Vally post");
    }
}

(3)創建代理類Agent,並實現HttpRequest接口,在代理類的構造方法中接受實際類,並在實現方法中通過實現類去調用。


/**
 * 代理類
 */
public class Agent implements HttpRequest {

    private HttpRequest request;

    public Agent(HttpRequest request) {
        this.request = request;
    }

    @Override
    public void get() {
        request.get();
    }

    @Override
    public void post() {
        request.post();
    }
}

(4)測試

package com.it.test.proxy;

public class Http {
    public static void main(String[] args) {
        HttpRequest httpRequest = new Agent(new Retrofit());
        httpRequest.get();
        httpRequest.post();

        HttpRequest httpRequest2 = new Agent(new Vally());
        httpRequest2.get();
        httpRequest2.post();
    }
}

在實現中,我們只需要創建代理類,並傳入具體的實際類。通過調用代理類的方法,其實內部完成實際類的調用。代理類,相當做了一層隔離。假如哪一天我們的實際類修改了,換成了別的。我們只需要修改傳入相應的實際類即可。
缺點:當哪一天我們的實際類實現了多個接口,增加了方法,這樣一來,代理類就沒法代理。因爲代理類的構造方法中只接受了一種類型。

二、動態代理

我們知道代理設計模式包含了三個對象

  • 代理接口
  • 代理類
  • 被代理的類
    被代理的類和代理類都實現了代理接口。在靜態代理中,代理類只能代理實現一個接口的類,所以當被代理類實現多個接口的時候,無法被代理,因此出現了動態代理。動態代理可以代理多個接口。

1、動態代理使用方法

(1)創建代理接口IWash、IMessage

package com.example.lib;

public interface IWash {
    void wash(String msg);
}

package com.example.lib;

public interface IMessage {

    void outMessage();
}

(2)創建被代理類,實現IWash和IMessage接口

package com.example.lib;

public class Luxi implements IMessage,IWash {
    @Override
    public void outMessage() {
        System.out.println("Luxi outMessage");
    }


    @Override
    public void wash(String msg) {
        System.out.println("Luxi wash"+msg);
    }
}

(3)通過Proxy.newProxyInstance創建代理對象

        /**
         *動態代理
         * Object o 代理對象
         *
         * luxi 被代理對象
         *
         */
        final Luxi luxi = new Luxi();
        InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };
        /**
         * 創建代理對象
         * Object o
         * newProxyInstance 方法會在底層生成一個代理類.class到內存中,
         * 而在代理類的構造方法中接受了一個InvocationHandler handler。
         * 我們傳入匿名內部類,實現其invoke方法,
         * 當我們通過代理對象調用代理接口方法的時候
         * 在代理類裏會通過傳入的handler調用invoke方法,並傳入 三個參數
         * (1)Object o 代理對象
         * (2)Method method 通過反射 獲取到的接口的方法,也就是代理類調用接口的方法。
         * (3)Object[] objects 方法的參數
         * 接着就會回調我們實現的invoke方法
         * 在invoke方法中通過反射 使用method 對象執行方法,傳入我們被代理的類對象執行方法,其中還包含了方法的參數
         *
         *
         *
         */
        Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );
        /**
         * 這個地方代理對象o之所以可以強轉成IMessage,
         * 又可以強轉成IWash
         * 是因爲代理類可以實現多個接口,
         * 所以可以強轉成任意接口類型
         *
         *
         */
        IMessage msg = (IMessage) o;
        msg.outMessage();
        IWash wash = (IWash) o;
        wash.wash("  hello world");

       // proxy();


    }

通過代理對象調用outMessage和wash方法, 最終執行了被代理對象 Luxi的outMessage和wash方法

Luxi outMessage
Luxi wash  hello world

2、動態代理原理分析

(1)創建動態代理對象,傳入InvocationHandler handler

   InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };
   
        Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );

我們通過Proxy.newProxyInstance方法傳入classLoader,代理接口的class數組、和InvocationHandler handler創建了一個代理對象。
我們知道創建對象肯定需要類,那麼此時我們需要創建一個代理類,才能實例化代理對象。因此在底層實現中首先會創建一個代理的類的class,也就是編譯之後的class文件。寫入到了內存。底層通過調用ProxyGenerator的generateProxyClass方法實現。爲了分析動態代理的原理,我們手動創建一個代理類。


    /**
     * 生成代理類
     */
    private static void proxy(){
        String name = IMessage.class.getName()+"$Proxy";
        //生成代理類 的Class數據
        byte [] bytes = ProxyGenerator.generateProxyClass(name,new Class[]{IMessage.class,IWash.class});
        try {
            FileOutputStream outputStream =new FileOutputStream("lib/"+name+".class");
            outputStream.write(bytes);
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

下面是我們生成的代理類IMessage$Proxy

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.example.lib;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class IMessage$Proxy extends Proxy implements IMessage, IWash {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public IMessage$Proxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void wash(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void outMessage() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}


也就是當我們調用 Object o = Proxy.newProxyInstance創建代理對象的時候,會先在內存中創建一個IMessageProxy的代理類,然後再通過實例化這個代理類創建代理對象。 我們看到IMessageProxy的構造方法中接受了一個InvocationHandler 類型的參數,也就是我們傳入的InvocationHandler handler ,你們內部類對象。實現了invoke方法。

  InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };

當通過代理對象調用裏面的wash方法的時候,就會調用super.h.invoke方法。

  public final void wash(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

而h又是父類的成員,接受的正式我們傳入的InvocationHandler 。

    protected Proxy(InvocationHandler var1) {
        Objects.requireNonNull(var1);
        this.h = var1;
    }

因此最終調用了我們內部類實現的invoke方法

  InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };

也就是創建代理對象,通過代理對象調用代理接口的方法最終會調用到了我們內部類的invoke方法,

invoke方法有三個參數,我們可以在源碼中看到。

   static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
   public final void wash(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
  • Object o對象指的是當前的代理對象
  • Method method就是源碼中的
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));

就是通過反射獲取代理接口中的方法,封裝成Method。

  • Object[] objects就是new Object[]{var1},通過代理對象調用方法的時候,我們方法傳入的參數,封裝成了一個數組。
    最後在invoke方法中,我們拿到以上的Method對象和參數數組Object[] objects,我們可以通過調用 method.invoke(luxi,objects);方法,從而達到調用了被代理對象Luxi luxi中的方法。因爲代理類和被代理都實現了同一個接口,因此代理類調用的方法,最終反射獲取到該方法,再讓被代理類調用完成最終的實現。
     final Luxi luxi = new Luxi();
        InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };

小結

  • 動態代理可以代理多個接口,靜態代理只能代理一個接口
  • 動態代理類不是通過我們手動生成,而是通過ProxyGenerator.generateProxyClass動態生成的一個class。
  • 動態代理類創建代理對象的時候需要傳入InvocationHandler 對象,而InvocationHandler 對象是一個接口,因此我們需要手動實現其中invoke方法,invoke方法包含了三個參數,當前代理類對象,Method對象(封裝了要代理的方法),Object[]參數數組(封裝了代理方法的參數值)
  • 當我們創建代理對象之後,調用了代理方法,接着在代理類的內部調用了invoke方法,接着回調到了我們實現的invoke方法
  • 在invoke方法中我們可以拿到代理的方法和參數,通過反射中method.invoke方法,傳入被代理的對象。最終調用了代理對象的方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章