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