一个基于RMI的小巧好用的框架

阅读更多

最近有用到rmi技术,需要实现Remote接口,需要抛出RemoteException异常,极其不爽,遂封装之,封装之后只需普通

POJO对象即可!

该框架核心有三个类,一个服务端类RMIEndpoint,一个客户端类RMIProxyFactory,一个通用接口GenericRmiService

 

先看一下用法:

 

服务端用法:

RMIEndpoint.addService(User.class, new UserImpl());
		try {
			RMIEndpoint.publish(8888);
		} catch (Exception e) {
			e.printStackTrace();
		}
 

 

 

客户端用法:

try {
			User user = RMIProxyFactory.getProxy(User.class, "localhost", 8888);
			System.out.println(user.say("11111"));
			System.out.println(user.say("11111"));
			System.out.println(user.say("11111"));
		} catch (Exception e) {
			e.printStackTrace();
		}
 

 

 

用起来简单吧!User是普通的接口,UserImpl是普通的POJO对象.

 

 

下面来看看三个核心类内部。

服务端点类:

package com.yuan.common.rmi;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.yuan.common.util.ReflectUtil;

public class RMIEndpoint {

	private static final Logger LOG = LoggerFactory.getLogger(RMIEndpoint.class);
			
	private static ConcurrentMap serviceMap = new ConcurrentHashMap();
	private static String HOSTNAME;
	
	public static void addService(Object service){
		serviceMap.put(service.getClass().getName(), service);
	}
	public static void addService(Class iface, Object service){
		serviceMap.put(iface.getName(), service);
	}
	
	/**
	 * 服务端多个IP则必须设置
	 * @param hostName
	 */
	public static void setHostName(String hostName){
		System.setProperty("java.rmi.server.hostname" , hostName); 
		HOSTNAME = hostName;
	}
	
	public static void publish() throws RemoteException, MalformedURLException, UnknownHostException{
		publish(1099);
	}
	public static void publish(int port) throws RemoteException, MalformedURLException, UnknownHostException{
		LocateRegistry.createRegistry(port); //注册端口
		
		GenericRmiService rmiService = new GenericRmiService(){
			private static final long serialVersionUID = 1L;

			public Object doService(String serviceName, String methodName, Object[] args) throws RemoteException {
				if(serviceMap.containsKey(serviceName)){
					Object service = serviceMap.get(serviceName);
					try {
						return ReflectUtil.execMethod(service, methodName, args);
					} catch (Exception e) {
						LOG.warn(e.getMessage(), e);
						throw new RemoteException(e.getMessage(), e);
					}
				}
				LOG.warn("RMI服务" + serviceName + "不存在!");
				throw new RemoteException("RMI服务" + serviceName + "不存在!");
			}
		};
		UnicastRemoteObject.exportObject(rmiService, 0); //随机通信端口
		if(HOSTNAME == null){
			HOSTNAME = InetAddress.getLocalHost().getHostAddress();
		}
		Naming.rebind("rmi://"+HOSTNAME+":"+port+"/GenericRmiService", rmiService);
	}
	
}
 

 

客户端代理工厂类:

package com.yuan.common.rmi;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.rmi.Naming;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class RMIProxyFactory {

	private static final ConcurrentMap proxyCache = new ConcurrentHashMap();
	
	public static void clearProxyCache(){
		proxyCache.clear();
	}
	
	public static  T getProxy(Class iface, String host, int port) throws Exception{
		final String serviceName = getServiceName(iface);
		if(proxyCache.containsKey(serviceName)){
			return (T)proxyCache.get(serviceName);
		}
		
		final GenericRmiService rmiService = (GenericRmiService)Naming.lookup("rmi://"+host+":"+port+"/GenericRmiService");
		
		InvocationHandler h = new InvocationHandler() {
			public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
				try {
					Object r = rmiService.doService(serviceName, method.getName(), args);
					return r;
				} catch (Exception e) {
					throw new RuntimeException(e.getMessage(), e);
				}
			}
		};
		
		Object proxy = Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, h);
		proxyCache.put(serviceName, proxy);
		return (T) proxy;
	}
	
	private static  String getServiceName(Class iface) throws IllegalArgumentException, IllegalAccessException{
		Field[] fs = iface.getFields();
		for(Field f : fs){
			if(f.getName().equals("SERVICENAME")){
				return (String)f.get(null);
			}
		}
		
		return iface.getName();
	}
}
 

 

 

RMI通用接口:

package com.yuan.common.rmi;

import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface GenericRmiService extends Remote, Serializable {

	public Object doService(String serviceName, String methodName, Object[] args)throws RemoteException;
	
}
 

 

 

User接口:

package tmp.rmi;

public interface User {

	public String say(String msg);
	
}
 

 

 

UserImpl对象:

 

package tmp.rmi;

public class UserImpl implements User {

	@Override
	public String say(String msg) {
		System.out.println("=== " + msg);
		System.out.println("=== " + Thread.currentThread());
		return "qqqqqqqqq";
	}

}
 

 

注意RMI支持并发访问,所以UserImpl必须是线程安全的!

 

附件中是完整源代码!

 

 

  • rmi.zip (7.4 KB)
  • 下载次数: 104

你可能感兴趣的:(rmi,proxy,endpoint,java)