`

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端的打印结果如下::




  • 大小: 33.6 KB
  • 大小: 14.5 KB
分享到:
评论

相关推荐

    JAVA的反射机制与动态代理

    Java的反射机制与动态代理是Java编程中两个非常重要的高级特性,它们在许多实际场景中发挥着关键作用,如框架开发、插件系统、元数据处理等。下面将详细讲解这两个概念及其应用。 首先,Java的反射机制允许我们在...

    JAVA反射机制详解

    最后,文章中提到了一个远程方法调用的例子,其中客户端通过反射机制的动态代理功能远程调用服务器端对象的方法。这个例子展示了Java反射机制在分布式计算中的应用,说明了反射在实现远程方法调用方面的重要性。 总...

    java反射机制详解

    Java 反射机制的实现主要靠 Java.lang.reflect 包中的类,包括 Class 类、Field 类、Method 类、Constructor 类和 Array 类。这些类提供了获取类的信息、构造对象、判断成员变量和方法、调用方法等功能。 在 Java ...

    JAVA RMI远程调用方法代码

    通过`Remote.class.getMethod()`获取该方法的`Method`对象,这是因为RMI底层使用了反射机制来实现远程方法调用。 ```java private static Method $method_getMemberAccountCount_5; static { try { $method_...

    Java反射与动态代理

    3. **远程调用**:如RMI(Remote Method Invocation),代理对象可以封装网络通信细节。 结合反射和动态代理,开发者可以构建更加灵活和强大的应用程序,实现高度抽象和解耦。但需要注意的是,过度使用反射和动态...

    java反射机制图文教程

    总之,Java反射机制是Java动态性的一个关键部分,它允许程序在运行时探索和操纵类的结构,以实现更灵活的代码设计。尽管反射可能带来一些性能损失,但在许多高级应用场景中,其优势远超其潜在的成本。在实际开发中,...

    C++反射机制实现

    利用宏定义和模板来实现反射机制能够提供编译时的类型检查,并且能够将反射机制与类型系统结合得更紧密。泛型编程也能够作为实现反射机制的手段之一,它允许在编译时对类型进行操作,提高了类型安全和性能。 文档中...

    java反射机制.pdf

    Java反射机制是Java编程语言中的一种强大的工具,它允许程序在运行时检查和操作类、接口、对象等的内部结构。这一机制的核心在于Java Reflection API,包含了一系列的类和接口,如`Class`, `Field`, `Method`, `...

    Java语言的反射机制.rar

    本章首先介绍了Java Reflection API的用法,然后介绍了一个远程方法调用的例子,在这个例子中客户端能够远程调用服务器端的一个对象的方法。服务器端采用了反射机制提供的动态调用方法的功能,而客户端则采用了反射...

    Java反射概念及例子

    反射技术的应用领域有很多,例如远程调用:客户端利用 socket 与服务端通信,发送要调用的类的方法和参数等信息,然后服务端利用反射技术调用指定的函数,返回结果给客户端。另外,反射技术也可以用来实现动态代理、...

    Java_Reflection_Programming.rar_Agent_java programming_反射

    学习和理解Java反射机制不仅有助于提升代码的灵活性和可扩展性,还能帮助开发者更好地理解和利用Java的许多高级特性,比如RMI、动态代理、注解处理器等。同时,熟练掌握反射机制也能为处理复杂的问题,如插件系统、...

    Java使用传统socket手写的远程RPC框架调用框架

    在RPC框架中,动态代理用于拦截客户端对服务接口的调用,将本地调用转换为远程调用。通过实现InvocationHandler接口,我们可以自定义调用处理逻辑,将方法名、参数等信息封装成请求消息,通过Socket发送给服务端。 ...

    java语言反射与动态代理学习笔记2(动态代理部分)

    在Java编程中,反射和动态代理是两个非常重要的高级特性,它们为程序提供了更大的灵活性和扩展性。这篇学习笔记主要关注动态代理部分,虽然没有提供具体的压缩包文件内容,但根据标题和描述,我们可以深入探讨这两个...

    类的反射机制您的网络连接,请

    4. **动态代理**:Java的Proxy类和InvocationHandler接口利用反射实现动态代理,可以创建满足特定接口的代理对象。 5. **框架开发**:许多Java框架如Spring、Hibernate都大量使用反射来实现依赖注入、AOP等高级功能...

    JAVA实现动态代理的简单流程

    动态代理,顾名思义,是在运行时动态创建代理对象的一种机制,它无需在编译期就确定代理类的具体实现,而是通过反射等技术在运行时自动生成代理类,从而达到灵活扩展原有接口功能的目的。这种机制广泛应用于AOP...

Global site tag (gtag.js) - Google Analytics