4.2 Java基础知识
在本节中,我们将简要介绍Hadoop RPC中用到的JDK开发工具包中的一些类。了解和掌握这些类的功能和使用方法是深入学习Hadoop RPC的基础。这些类主要来自以下三个Java包:java.lang.reflect(反射机制和动态代理相关类)、java.net(网络编程库)和java.nio(NIO)。
4.2.1 Java反射机制与动态代理
反射机制是Java语言的一个重要特性,它允许用户动态获取类的信息和动态调用对象的方法。它提供的类及类对应的功能如下。
❑Class类:代表一个Java类。
❑Field类:代表Java类的属性。
❑Method类:代表Java类的方法。
❑Constructor类:代表Java类的构造函数。
❑Array类:提供了动态创建数组,以及访问数组元素的静态方法。
❑Proxy类以及InvocationHandler接口:提供了动态生成代理类以及实例的方法。
接下来重点介绍Java动态代理。介绍Java动态代理之前,先介绍“代理”这一概念。代理是一种常用的设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。代理类负责为委托类进行预处理(如安全检查,权限检查等)或者执行完后的后续处理(如转发给其他代理等)。
Java动态代理机制的实现,使得开发人员通过简单地指定一组接口及委托类对象,便能动态地获得代理类,这大大简化了编写代理类的步骤。
要学习Java动态代理机制,需要首先了解以下几个类或接口。
(1)java. lang.reflect.Proxy
这是Java动态代理机制的主类,它提供了一组静态方法,用于为一组接口动态地生成代理类及其对象。java.lang.reflect.Proxy的具体实现如下:
//方法1:获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
//方法2:获取关联于指定类装载器和一组接口的动态代理类的对象
static Class getProxyClass(ClassLoader loader, Class[]interfaces)
//方法3:判断指定的类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
//方法4:为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[]interfaces, InvocationHandler h)
(2)java. lang.reflect.InvocationHandler
这是调用处理器接口。它定义了一个invoke方法,用于处理在动态代理类对象上的方法调用。通常开发人员需实现该接口,并在invoke方法中实现对委托类的代理访问。invoke方法声明如下:
//该方法负责处理动态代理类上的所有方法调用。包含三个参数,分别表示代理类实例
//被调用的方法对象、调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上执行
Object invoke(Object proxy, Method method, Object[]args)
一个典型的动态代理创建对象的过程可分为以下4个步骤:
步骤1 通过实现InvocationHandler接口创建自己的调用处理器:
InvocationHandler handler=new InvocationHandlerImpl(……);
步骤2 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类:
Class clazz=Proxy.getProxyClass(classLoader, new Class[]{……});
步骤3 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型:
Constructor constructor=clazz.getConstructor(new Class[]{InvocationHandler.class});
步骤4 通过构造函数创建动态代理类实例,此时需将调用处理器对象作为参数被传入:
Interface Proxy=(Interface)constructor.newInstance(new Object[]{handler});
为了简化对象创建过程,Proxy类中的newInstance方法封装了步骤2~步骤4,只需两步即可完成代理对象的创建。代码清单4-1给出一个详细的动态代理创建对象的实例:Server类提供了计算整型数相加和相减的两个方法,用户可直接通过创建代理对象访问这两个方法(类似于RPC Client)。
代码清单4-1 Java动态代理示例程序
interface CalculatorProtocol{//定义一个接口协议
public int add(int a, int b);//两个数相加
public int subtract(int a, int b);//两个数相减
}
class Server implements CalculatorProtocol{//实现接口协议
public int add(int a, int b){
return a+b;
}
public int subtract(int a, int b){
return a-b;
}
}
//实现调用处理器接口
class CalculatorHandler implements InvocationHandler{
private Object objOriginal;
public CalculatorHandler(Object obj){
this.objOriginal=obj;
}
public Object invoke(Object proxy, Method method, Object[]args)
throws Throwable{
//可添加一些预处理
Object result=method.invoke(this.objOriginal, args);
//可添加一些后续处理
return result;
}
}
//测试用例
public class DynamicProxyExample{
public static void main(String[]args){
CalculatorProtocol server=new Server();//创建Server
InvocationHandler handler=new CalculatorHandler(server);
CalculatorProtocol client=(CalculatorProtocol)Proxy.newProxyInstance(server.
getClass().getClassLoader(),server.getClass().getInterfaces(),handler);
//创建一个Client
int r=client.add(5,3);
System.out.println("5+3="+r);
r=client.subtract(10,2);
System.out.println("10-2="+r);
}
}