java 反射机制(五)利用代理实现远程调用

SimpleClient客户端通过HelloService代理类来调用SimpleServer
服务器端的HelloServiceImpl 对象的方法。客户端的HelloService 代理类也实现了
HelloService 接口,这可以简化SimpleClient 客户端的编程。对于SimpleClient 客户端而言,与远程服务器的通信的细节被封装到HelloService代理类中。SimpleClient客户端可以按照以下方式调用远程服务器上的HelloServiceImpl对象的方法:
//创建HelloService 代理类的对象
HelloService helloService1=new HelloServiceProxy(connector);//通过代理类调用远程服务器上的HelloServiceImpl 对象的方法
System.out.println(helloService1.echo("hello"));
从以上程序代码可以看出,SimpleClient客户端调用远程对象的方法的代码与调用
本地对象的方法的代码很相似,由此可以看出,代理类简化了客户端的编程。
Connector 类负责建立与远程服务器的连接,以及接收和发送Socket对象。如例程
10-17 所示是Connector 类的源程序。
例程10-17 Connector.java
package reflection.proxy.dynamic;

import java.io.*;
import java.net.*;
//Connector 类负责建立与远程服务器的连接,以及接收和发送Socket对象
public class Connector {
	private String host;
	private int port;
	private Socket skt;
	private InputStream is;
	private ObjectInputStream ois;
	private OutputStream os;
	private ObjectOutputStream oos;

	public Connector(String host, int port) throws Exception {
		this.host = host;
		this.port = port;
		connect(host, port);
	}

	public void send(Object obj) throws Exception { // 发送对象
		oos.writeObject(obj);
	}

	public Object receive() throws Exception { // 接收对象
		return ois.readObject();
	}

	public void connect() throws Exception { // 建立与远程服务器的连接
		connect(host, port);
	}

	public void connect(String host, int port) throws Exception { // 建立与远程服务器的连接
		skt = new Socket(host, port);
		os = skt.getOutputStream();
		oos = new ObjectOutputStream(os);
		is = skt.getInputStream();
		ois = new ObjectInputStream(is);
	}

	public void close() { // 关闭连接
		try {
		} finally {
			try {
				ois.close();
				oos.close();
				skt.close();
			} catch (Exception e) {
				System.out.println("Connector.close: " + e);
			}
		}
	}
}

HelloService代理类有两种创建方式:一种方式是创建一个HelloServiceProxy静态
代理类,如例程10-18 所示;还有一种方式是创建HelloService的动态代理类,如例程
10-19 所示ProxyFactory 类的静态getProxy()方法就负责创建HelloService 的动态代理类,并且返回它的一个实例。
例程10-18 HelloServiceProxy.java(静态代理类)
package reflection.proxy.dynamic;

import java.rmi.RemoteException;
import java.util.Date;

public class HelloServiceProxy implements IHelloService {
	private String host;
	private int port;

	public HelloServiceProxy(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public String echo(String msg) throws RemoteException {
		Connector connector = null;
		try {
			connector = new Connector(host, port);
			Call call = new Call("reflection.proxy.dynamic.IHelloService",
					"echo", new Class[] { String.class }, new Object[] { msg });
			connector.send(call);
			call = (Call) connector.receive();
			Object result = call.getResult();
			if (result instanceof Throwable)
				throw new RemoteException("", (Throwable) result); // 把异常都转换为RemoteException
			else
				return (String) result;
		} catch (Exception e) {
			throw new RemoteException("", e); // 把异常都转换为RemoteException
		} finally {
			if (connector != null)
				connector.close();
		}
	}

	public Date getTime() throws RemoteException {
		Connector connector = null;
		try {
			connector = new Connector(host, port);
			Call call = new Call("reflection.proxy.dynamic.IHelloService",
					"getTime", new Class[] {}, new Object[] {});
			connector.send(call);
			call = (Call) connector.receive();
			Object result = call.getResult();
			if (result instanceof Throwable)
				throw new RemoteException("", (Throwable) result); // 把异常都转换为RemoteException
			else
				return (Date) result;
		} catch (Exception e) {
			throw new RemoteException("", e); // 把异常都转换为RemoteException
		} finally {
			if (connector != null)
				connector.close();
		}
	}
}

例程10-19 ProxyFactory.java(负责创建动态代理类及其实例)
package reflection.proxy.dynamic;

import java.lang.reflect.*;
import java.rmi.RemoteException;
public class ProxyFactory {//动态代理
	public static Object getProxy(final Class classType, final String host,
			final int port) {
		InvocationHandler handler = new InvocationHandler() {
			public Object invoke(Object proxy, Method method, Object args[])
					throws Exception {
				Connector connector = null;
				try {
					connector = new Connector(host, port);
					Call call = new Call(classType.getName(), method.getName(),
							method.getParameterTypes(), args);
					connector.send(call);
					call = (Call) connector.receive();
					Object result = call.getResult();
					if (result instanceof Throwable)
						throw new RemoteException("",(Throwable) result); // 把异常都转换为RemoteException
					else
						return result;
				} finally {
					if (connector != null)
						connector.close();
				}
			}
		};
		return Proxy.newProxyInstance(classType.getClassLoader(),
				new Class[] { classType }, handler);
	}
}

无论HelloService 的静态代理类还是动态代理类,都通过Connector 类来发送和
接收Call 对象。ProxyFactory 工厂类的getProxy()方法的第一个参数classType 指定代理类实现的接口的类型,如果参数classType 的取值为HelloService.class,那么
getProxy()方法就创建HelloService 动态代理类的实例。如果参数classType 的取值为Foo.class,那么getProxy()方法就创建Foo动态代理类的实例。由此可见,getProxy()
方法可以创建任意类型的动态代理类的实例,并且它们都具有调用被代理的远程对象
的方法的能力。
如果使用静态代理方式,那么对于每一个需要代理的类,都要手工编写静态代理
类的源代码;如果使用动态代理方式,那么只要编写一个动态代理工厂类,它就能自
动创建各种类型的动态代理类,从而大大简化了编程,并且提高了软件系统的可扩展
性和可维护性。
如例程10-20 所示的SimpleClient类的main()方法中,分别通过静态代理类和动态
代理类去访问SimpleServer 服务器上的HelloServiceImpl对象的各种方法。
例程10-20 SimpleClient.java简单的客户端:
package reflection.proxy.dynamic;
public class SimpleClient {
	public static void main(String args[]) throws Exception {
		// 创建静态代理类实例
		IHelloService helloService1 = new HelloServiceProxy("localhost", 8888);
		System.out.println(helloService1.echo("hello"));
		System.out.println(helloService1.getTime());
		// 创建动态代理类实例
		IHelloService helloService2 = (IHelloService) ProxyFactory.getProxy(
				IHelloService.class, "localhost", 8888);
		System.out.println(helloService2.echo("hello"));
		System.out.println(helloService2.getTime());
	}
}

服务器端:
package reflection.proxy.dynamic;

import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;

public class SimpleServer {
	private Map remoteObjects = new HashMap(); // 存放远程对象的缓存

	/** 把一个远程对象放到缓存中 */
	public void register(String className, Object remoteObject) {
		remoteObjects.put(className, remoteObject);
	}

	public void service() throws Exception {
		ServerSocket serverSocket = new ServerSocket(8888);
		System.out.println("服务器启动......");
		while (true) {
			Socket socket = serverSocket.accept();

			InputStream in = socket.getInputStream();
			ObjectInputStream ois = new ObjectInputStream(in); // 读取对象
			OutputStream out = socket.getOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(out);

			Call call = (Call) ois.readObject(); // 接收客户发送的Call 对象

			System.out.println(call); // toString()方法

			call = invoke(call); // 调用相关对象的方法
			oos.writeObject(call); // 向客户发送包含了执行结果的Call 对象
			ois.close();
			oos.close();
			socket.close();
		}
	}

	public Call invoke(Call call) {
		Object result = null;
		try {
			String className = call.getClassName();
			String methodName = call.getMethodName();
			Object[] params = call.getParams();
			Class classType = Class.forName(className);
			Class[] paramTypes = call.getParamTypes();

			Method method = classType.getMethod(methodName, paramTypes);
			Object remoteObject = remoteObjects.get(className); // 从缓存中取出相关的远程对象
			if (remoteObject == null) {
				throw new Exception(className + "的远程对象不存在");
			} else {
				result = method.invoke(remoteObject, params);
			}
		} catch (Exception e) {
			result = e;
		}
		call.setResult(result); // 设置方法执行结果
		return call;
	}

	public static void main(String args[]) throws Exception {

		SimpleServer server = new SimpleServer();
		// 把事先创建的HelloServiceImpl 对象加入到服务器的缓存中
		server.register("reflection.proxy.dynamic.IHelloService", new HelloServiceImpl());
		server.service();
	}
}

先运行命令“java proxy1.SimpleServer”,再运行命令“java proxy1.SimpleClient”,
SimpleClient端的打印结果如下::

java 反射机制(五)利用代理实现远程调用


你可能感兴趣的:(java,编程,.net,socket,OS)