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);

}

}