zoukankan      html  css  js  c++  java
  • 远程服务调用(RMI)

    模块概念的引入,是本框架的一大优势,而跨JVM的远程服务调用则是另一个最有价值的功能。

    《本地服务调用》一文中我们讲解了跨模块间的服务调用可以是这样的:

    ServiceHelper.invoke("pas","AuthService:auth",new Data("principal",principalInstance,"url","http://localhost:8080/pas/index.shtml"));

    如果这个pas不是本地模块,而是远程模块,又该如何调用呢?

    正如你期望的那样,还是上面这样调用,这意味着,无论这个pas模块部署在什么地方,你得代码复杂度没有变化。可怜了那些靠代码量体现工作量的程序猿们,处理了一个如此复杂的工作,还是这么简单的两行代码。

    远程服务的实现方法

    flying中是通过hessian来实现远程调用的,主要是因为hessian简单、功能够用。

    服务提供端代码:

    1、定义Hessian服务提供接口

    public interface RemoteService {

    RemoteValue invoke(Principal principal, String moduleId, String serviceId, RemoteValue request) throws Exception;

    }

    2、定义Hessian的Servlet

    @WebServlet(value="/remoting")

    public class HessianRemoteService extends HessianServlet implements RemoteService{

    private final static Logger logger = Logger.getLogger(HessianRemoteService.class);

    public void init(ServletConfig servletConfig) throws ServletException {

    super.init(servletConfig);

    }

    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest)servletRequest;

    long start = System.currentTimeMillis();

    final String requestURI = req.getRequestURI() + (req.getQueryString() == null?"":"?" + req.getQueryString());

    try {

    super.service(servletRequest, servletResponse);

    } finally {

    logger.info("Access(" + (System.currentTimeMillis() - start) + ")\tURI:" + requestURI);

    }

    }

    public RemoteValue invoke(Principal principal, String moduleId, String serviceId, RemoteValue remoteData) throws Exception {

    long start = System.currentTimeMillis();

    try {

    Data req = remoteData.getValue();

    LocalModule module = Application.getInstance().getModules().getLocalModule(moduleId);

    ThreadContext.getContext().reset(module, serviceId, req, principal);

    ThreadContext.getContext().setInvokeType(ThreadContext.InvokeType.Remote);

    Data result = module.invoke(serviceId, req);

    remoteData.setValue(result);

    } catch (Exception e){

    remoteData.setException(e);

    } finally {

    logger.info("RemoteInvoker(" + (System.currentTimeMillis() - start) + ")\tModuleId:" + moduleId+";ServiceId:" + serviceId);

    }

    return remoteData;

    }

    }

    3、实现Hessian调用的客户端

    public class HessianRemoteServiceInvoker implements RemoteServiceInvoker {

    @Override

        public Data invoke(Principal principal, LocalModule localModule, String remoteModuleId, String serviceId, Data request)

                throws Exception {

             if (localModule == null) {

                 localModule = ThreadContext.getContext().getModule();

             }

             if (localModule != null) {

                 Thread.currentThread().setContextClassLoader(localModule.getClassLoader());

             }

             String url = Application.getInstance().getModules().getRemoteModule(remoteModuleId).getPath();

            

                 RemoteService remoteService = getRemoteService(url);

                 Map<String, Object> nonSerializable = request.filterValues(new DataFilter(){

    @Override

    public boolean isValid(String key, Object value) {

    return key != null && value != null && (value instanceof Serializable);

    }

                        

                 });

                 final RemoteValue res = remoteService.invoke(principal, remoteModuleId, serviceId, new RemoteValue(request));

             if (res.getException() != null) {

                 throw (Exception) res.getException();

             } else {

                 return res.getValue().putAll(nonSerializable);

             }

        }

        private static Map<String,RemoteService> remoteServiceMap = new ConcurrentHashMap<String, RemoteService>();

        private static Object lock = new Object();

       

        private RemoteService getRemoteService(String url) throws Exception {

                RemoteService remoteService = remoteServiceMap.get(url);

                if(remoteService==null){

                        synchronized (lock) {

                                remoteService = remoteServiceMap.get(url);

                                if(remoteService==null){

                                        HessianProxyFactory factory = new HessianProxyFactory(Thread.currentThread().getContextClassLoader());

                                        HttpClientHessianConnectionFactory hessianConnectionFactory = HttpClientHessianConnectionFactory.getInstance();

                                //hessianConnectionFactory.addHeader("authorization", "admin");

                                factory.setConnectionFactory(hessianConnectionFactory);

                               

                    final Data config = Application.getInstance().getConfigs("hessian");

                                if (config != null) {

                                    factory.setConnectTimeout(config.getLong("connectTimeout", 10000l));

                                    factory.setReadTimeout(config.getLong("readTimeout", 10000l));

                                    factory.setHessian2Reply(config.getBoolean("hessian2Reply", true));

                                    factory.setHessian2Request(config.getBoolean("hesian2Request", false));

                                    factory.setChunkedPost(config.getBoolean("chunkedPost", true));

                                    factory.setDebug(config.getBoolean("debug", false));

                                }

                                remoteService = (RemoteService) factory.create(RemoteService.class, url);

                                remoteServiceMap.put(url, remoteService);

                                }

    }

                }

                

            return remoteService;

        }

    }

    4、实现RemoteModule中的invoke方法:

    public Data invoke(String serviceId, Data request) throws Exception {

    return RemoteServiceInvokerHelper.invoke(remoteServiceInvoker, id, serviceId, request);

    }

    框架源码:https://github.com/hifong/flying

    博客空间:http://www.cnblogs.com/hifong/

    Demo应用:https://github.com/hifong/pas

    技术QQ群:455852142

  • 相关阅读:
    Unix配置定时执行任务
    在Mac上使用Make编译时出现clang: error: unsupported option '-fopenmp'的解决办法
    git的一些操作
    Github误上传多余的文件夹后解决办法
    Ubuntu18.04安装使用YOLOv3
    本地IDEA中使用Spark直连集群上的Hive
    如何利用dokcer提交我的比赛代码
    Activiti7之整合spring和spring boot
    Activiti7之网关
    Activiti7之组任务
  • 原文地址:https://www.cnblogs.com/hifong/p/5440803.html
Copyright © 2011-2022 走看看