RPC中用到的 *動態代理,反射機制,NIO

今天在學習RPC協議時,用到了動態代理和反射機制

所以,我們先來看看動態機制:在java的動態代理中,有兩個重要的類或接口,一個是InvocationHandler(Interface),另一個則是Proxy(Class0,這一個類和接口。首先我們來看看java的api對這兩個類的描述


InvocationHandler:
InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一個動態代理類都必須要實現InvocationHadler這個接口,並且每個代理類實例都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由InvocationHandler這個接口的invoke方法來進行調用。

我們來看看這個唯一的方法invoke

Object invoke(Object proxy,Method method,Object[] args)throws Throwable

這三個參數所代表的含義在我看來分別是:

proxy:指我們要代理的那個真實的對象

method:指代的是我們所要調用真是對象的某個方法的Method對象

args:指代的是調用真實對象某個方法時接受的參數。

然後,我們來看看Proxy這個類

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 
Proxy這個類的作用就是用來動態創建一個代理對象的類,它提供了許多的方法,但是我們用的最多的就是 newProxyInstance 這個方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

這個方法的作用就是得到一個動態代理的對象,

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

她也有三個參數,這三個參數的意思爲:

loader:一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代碼對象進行加載

interfance:一個Interface對象的數組,表示的是我將要給我所需要代理對象提供一組什麼接口,如果我提供了一組接口給他,那麼這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了。

h:一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上。

一個關於動態代理的小實例:

之前在網上看了很多,發現都是錯的,在此附上自己寫的

(1)我們定義一個接口:真實的對象

(2)實現接口

(3)代理類:實現InvocationHanlder接口:注意,這裏我們要用到反射機制,讓他去調用自身的類,使用網上的Subject在做客戶端測試時,是找不到方法的

(4)客戶端測試

下面附上源代碼

public interface RealProxy {
    public void call();
}

public class RealProxyImpl implements RealProxy{


@Override
public void call() {
// TODO Auto-generated method stub
System.out.println("被代理類");
}
}

public class DLproxy implements InvocationHandler{
//先定義一個對象
private Object sum;
public DLproxy(){}
public DLproxy(Object obj ){
sum=obj;
}

//之前並沒有寫這個方法,發現是不對的,但是一直想不通,爲什麼不能直接在客戶端進行代用,之後發現,有可能是subject方法的沒法調用
public Object createProxy(Object sum){
this.sum=sum;
return Proxy.newProxyInstance(this.sum.getClass().getClassLoader(), this.sum.getClass().getInterfaces(), this);

}
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
RealProxyImpl ps=(RealProxyImpl) this.sum;
System.out.println("call before"+method);
//invoke(proxy, method, args);

System.out.println("call after"+method);
return method.invoke(sum, args);
}
    
}

public class TextProxy {


public static void main(String[] args) {
DLproxy pro=new DLproxy();
RealProxyImpl ps=new RealProxyImpl();
RealProxy ps1=(RealProxy) pro.createProxy(ps);
ps1.call();
// RealProxy rp=new RealProxyImpl();
// Subject subject=(Subject) Proxy.newProxyInstance(rp.getClass().getClassLoader(), rp.getClass().getInterfaces(), (InvocationHandler) rp);
 
}


}


反射機制

其實理解Java的反射和理解JavaScript的eval函數一樣,都是將一個字符型數據轉換爲相應的類、屬性和方法

官方說法爲:

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

在我看來,反射,就是我們可以任意的去調用一個類的所有方法。

附上代碼

/**
 * 反射機制的實現
 * @author root
 *
 */
public class User {
private String name;


    private int age;


    public User() {
        name = "無名氏";
        age = 22;
    }


    public User(String name) {
        this.name = name;
        this.age = 22;
    }


    public String toString() {
        return "名字是:" + name;
    }


    public String toString(int age, String name) {
        this.name = name;
        this.age = age;
        return "名字是:" + name + ";年齡是:" + age;
    }

public static void main(String[] args) {
/**
* 我們之前的方法
*/
User accpTeacher = new User();
    System.out.println(accpTeacher);
    /**
     * // 實例化一個類
     * 
     * 首先Class.forName(類名)是將這個類加載到JVM虛擬機中,
     * 獲得一個類型爲Class的類,然後調用其newInstance()方法,相當於實例化(調用無參的構造函數);
     * 所以以上兩段代碼的運行效果是一致的。
     */
try {
Object user = Class.forName(User.class.getName()).newInstance();
System.out.println(user);
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
    /**
     * 通過構造方法實例化一個類,本例是一個有參數的構造函數,並且構造函數可以爲private修飾
     */
Class[] argtype=new Class[]{String.class};//代表構造方法的參數
Object[] argparam=new Object[]{"張三"};//代表構造方法的參數值
try {
Class classtype=Class.forName(User.class.getName());
//獲得構造方法,argtype是參數類型數組,我們這裏代表的是參數只有一個string類型
Constructor constructor=classtype.getDeclaredConstructor(argtype);
//訪問私有構造函數,Spring可喲配置私有的屬性和方法,其實就是用到這裏
constructor.setAccessible(true);
Object user2=constructor.newInstance(argparam);
System.out.println(user2);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


NIO的實現

概念引用:

NIO 有一個主要的類Selector,這個類似一個觀察者,只要我們把需要探知的socketchannel告訴Selector,我們接着做別的事情,當有事件發生時,他會通知我們,傳回一組SelectionKey,我們讀取這些Key,就會獲得我們剛剛註冊過的socketchannel,然後,我們從這個Channel中讀取數據,放心,包準能夠讀到,接着我們可以處理這些數據。

Selector內部原理實際是在做一個對所註冊的channel的輪詢訪問,不斷的輪詢(目前就這一個算法),一旦輪詢到一個channel有所註冊的事情發生,比如數據來了,他就會站起來報告,交出一把鑰匙,讓我們通過這把鑰匙來讀取這個channel的內容。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章