RPC中用到的 *动态代理,反射机制,NIO

来源:互联网 发布:桃木剑淘宝 编辑:程序博客网 时间:2024/05/16 01:01

今天在学习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的内容。


0 0