yuancihang 发表于 2013-2-3 14:09:11

一个基于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<String, Object> serviceMap = new ConcurrentHashMap<String, Object>();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<String, Object> proxyCache = new ConcurrentHashMap<String, Object>();public static void clearProxyCache(){proxyCache.clear();}public static <T> T getProxy(Class<T> 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 <T> String getServiceName(Class<T> 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 {@Overridepublic String say(String msg) {System.out.println("=== " + msg);System.out.println("=== " + Thread.currentThread());return "qqqqqqqqq";}}  
注意RMI支持并发访问,所以UserImpl必须是线程安全的!
 
附件中是完整源代码!
 
 
页: [1]
查看完整版本: 一个基于RMI的小巧好用的框架