通过HTTP方式实现远程调用对象

    我们知道HTTP是一种超文本传输协议,其中两个比较重要的对象是HttpRequest和HttpResponse,HTTP协议可以实现文本内容的传输和文件传输。本文将通过HTTP的文件传输实现远程调用对象功能。

    由于最近在做一个定时器集群管理项目,需要远程去控制定时器应用内部的定时器运行状态,比如获取当前应用的所有TimerJOb的实例对象,比如对某个定时器任务进行暂停,重启以及重新调整定时器运行参数,例如:将每小时运行一次调整为每两个小时运行一次,而不需要重启远程的应用。在这个过程中需要运用到远程调用对象的功能,该项目提供了两种方式实现该功能,一种是RPC,另一种是HTTP。本文将主要对HTTP的实现进行描述。

    首选先描述一下我的实现思路。通过java内部的InvocationHandler和Proxy进行产生远程对象接口的一个代理对象,于是在InvocationHandler内部就可以拦截代理对象调用的每个方法,那么在拦截方法调用后,将调用的方法名称,参数以及调用接口信息封装成一个调用的对象,并且将该对象进行序列化,通过HTTP的文件参数到远程的应用上面,远程应用在通过反序列化将解析出需要调用的那个类以及哪个方法,并且调用执行,然后将执行结果通过Response的writer写回,这样就可以在调用者完全不知道的情况下,去远程访问某个对象以及返回执行结果,使用过程和调用本地方法一样。下面将对具体实现进行描述。

    为了实现这一功能,我创建一个Helper类,该类结构如下:


public class HttpRequestHelper implements Serializable {

	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = -600087221405366543L;
	private String methodName;
	private Object[] args;
	private String url;

	/**
	 * @return the methodName
	 */
	public String getMethodName() {
		return methodName;
	}

	/**
	 * @return the args
	 */
	public Object[] getArgs() {
		return args;
	}

	/**
	 * @param methodName
	 *            the methodName to set
	 */
	private HttpRequestHelper setMethodName(String methodName) {
		this.methodName = methodName;
		return this;
	}

	/**
	 * @param args
	 *            the args to set
	 */
	private HttpRequestHelper setArgs(Object[] args) {
		this.args = args;
		return this;
	}

	/**
	 * @param url
	 *            the url to set
	 */
	private HttpRequestHelper setUrl(String url) {
		this.url = url;
		return this;
	}

	@SuppressWarnings("unchecked")
	public static <T extends Object> T getProxy(Class<T> serviceInterface,
			final String url) {
		InvocationHandler handler = new InvocationHandler() {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				HttpRequestHelper requestHelper = new HttpRequestHelper();
				requestHelper.setArgs(args).setUrl(url)
						.setMethodName(method.getName());
				Object result = requestHelper.invoke();
				if (Exception.class.isAssignableFrom(result.getClass())) {
					Exception e = (Exception) result;
					throw e;
				}
				return result;
			}
		};
		return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(),
				new Class<?>[] { serviceInterface }, handler);
	}

	private Object invoke() throws IOException, ClassNotFoundException {
		HttpClient client = new HttpClient(new HttpClientParams(),
				new SimpleHttpConnectionManager(true));
		PostMethod post = new PostMethod(this.url);
		post.getParams().setContentCharset("UTF-8");
		try {
			byte[] bytes = serializableObject(this);
			File tempFile = writeObjectToTempFile(bytes);
			FilePart filePart = new FilePart("tempFile", tempFile.getName(),
					tempFile);
			Part[] parts = new Part[1];
			parts[0] = filePart;
			MultipartRequestEntity mrp = new MultipartRequestEntity(parts,
					post.getParams());
			post.setRequestEntity(mrp);
			client.executeMethod(post);
			tempFile.deleteOnExit();
			return unSerializableObject(post.getResponseBody());
		} catch (Exception e) {
			return e;
		} finally {
			post.releaseConnection();
		}
	}

	private static File writeObjectToTempFile(byte[] contents)
			throws IOException {
		String fileName = String.valueOf(System.currentTimeMillis());
		File tempFile = new File(HttpRequestHelper.class.getResource("/").getPath()
				+ fileName);
		FileOutputStream outputStream = new FileOutputStream(tempFile);
		outputStream.write(contents, 0, contents.length);
		outputStream.flush();
		outputStream.close();
		return tempFile;
	}

	private static byte[] serializableObject(Object object) throws IOException {
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		ObjectOutputStream out = new ObjectOutputStream(byteArrayOutputStream);
		out.writeObject(object);
		return byteArrayOutputStream.toByteArray();
	}

	private static Object unSerializableObject(byte[] bytes) throws IOException,
			ClassNotFoundException {
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
				bytes);
		ObjectInputStream input = new ObjectInputStream(byteArrayInputStream);
		return input.readObject();
	}
}

该类只对外暴露了一个静态方法(除了get方法)getProxy,该方法便是为你要调用远程接口创建一个代理对象,远程地址则是你通过getProxy方法设置进来,在该方法体内通过jdk自身的InvocationHandler来拦截这个代理对象请求的每个方法,当通过代理对象调用某个方法时,则会拦截请求的方法对象,请求的参数,然后将信息封装到HttpRequestHelper中,将HttpRequestHelper对象进行序列化,并且将序列化的字节数组写到一个临时文件,然后通过对这个临时文件传输到远程的服务,便达到了将HttpRequestHelper对象传输到远程服务,远程服务再通过反序列化HttpRequestHelper对象,便知道是调用哪个服务,以及调用服务的哪个方法,然后执行对应服务的对应方法,将结果再进行序列化成字节数组,通过response的wirter将结果写回请求应用,这边完成了整个的请求过程。对于远程服务处理请求代码,下面粘贴处一个Filter的实现类,用于接受该类请求

public boolean service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		HttpServletRequest request = (HttpServletRequest) req;
		OutputStream outputStream = res.getOutputStream();
		req.setCharacterEncoding("UTF-8");
		DemoService slaveEndService = new DemoServiceImpl();
		byte[] content = null;
		try {
			content = readHttpObjectByte(request);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		try {
			HttpRequestHelper requestHelper = (HttpRequestHelper) unSerializableObject(content);
			Object result = slaveEndService.serviceDispatche(
					requestHelper.getMethodName(), requestHelper.getArgs());
			outputStream.write(serializableObject(result));
			outputStream.flush();

		} catch (ClassNotFoundException e) {
			outputStream.write(serializableObject(e));
			outputStream.flush();
		} finally {
			outputStream.close();
		}
		return true;
	}
	@SuppressWarnings("rawtypes")
	private static byte[] readHttpObjectByte(HttpServletRequest request)
			 {
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		byte[] content = null;
		if (isMultipart) {
			FileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload upload = new ServletFileUpload(factory);
			try {
				Iterator items = upload.parseRequest(request).iterator();
				while (items.hasNext()) {
					FileItem item = (FileItem) items.next();
					if (!item.isFormField()) {
						InputStream is = item.getInputStream();
						ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
						byte[] buff = new byte[1024];
						int off = 0;
						while ((off = is.read(buff, 0, 1024)) != -1) {
							arrayOutputStream.write(buff, 0, off);
						}
						content = arrayOutputStream.toByteArray();
						arrayOutputStream.flush();
						arrayOutputStream.close();
						is.close();
					}
				}
			} catch (Exception e) {
				 
			}
		}
		return content;
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
	 * javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	@Override
	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		if (!service(req, res)) {
			chain.doFilter(req, res);
		}

	}


你可能感兴趣的:(代理,http,对象序列化,远程对象调用,对象反序列化)