zoukankan      html  css  js  c++  java
  • 基于Rest服务实现的RPC

      前言:现在RPC成熟的框架已经很多了,比喻Motan和Dubbo,但是今天我这里提供一种基于Rest服务的Rpc。和上一篇连着的http://www.cnblogs.com/LipeiNet/p/5856414.html

    1:原理

    首先我们要建立一个Rest服务,如果其他应用程序想要获取这个服务的资源就只需要一个URI就可以了。但是由于内部程序的调用我们在通过URI获取json然后在自己处理很不方便,也不是很合适,那么我们就需要利用一个中间层,把访问Rest服务返回的资源重新包装,然后其他工程只需要调用这个rpc工程即可。如下图

    2:实现Rest服务

    2.1:定义一个用于返回给消费者的实现对象(自己约定的)

    public class ResponseBean implements Serializable{
        private static final long serialVersionUID = -1L;
        public static final int SUCCESS = 10;
        public static final int FAILURE = 20;
        public static final int LOCKED = 30;
        public static final int EXCEPTION = 40;
        private int returnCode;//返回给消费者的编码(0表示调用成功,1表示调用失败)
        private String returnMsg;//返回给消费者错误信息
        private int dataCount;//用于返回int类型
        private String returnData;//用户返回json
        private Object returnObject;//用于返回对象
    
        public ResponseBean() {
        }
    
        public ResponseBean(int returnCode, String returnMsg) {
            this.returnCode = returnCode;
            this.returnMsg = returnMsg;
        }
    
        public Object getReturnObject() {
            return this.returnObject;
        }
    
        public void setReturnObject(Object returnObject) {
            this.returnObject = returnObject;
        }
    
        public int getDataCount() {
            return this.dataCount;
        }
    
        public void setDataCount(int dataCount) {
            this.dataCount = dataCount;
        }
    
        public String getReturnData() {
            return this.returnData;
        }
    
        public void setReturnData(String returnData) {
            this.returnData = returnData;
        }
    
        public int getReturnCode() {
            return this.returnCode;
        }
    
        public void setReturnCode(int returnCode) {
            this.returnCode = returnCode;
        }
    
        public String getReturnMsg() {
            return this.returnMsg;
        }
    
        public void setReturnMsg(String returnMsg) {
            this.returnMsg = returnMsg;
        }
    }

    2.2:定一个供外部请求的ApiService

    public interface ApiService {
         String getToken();
         ResponseBean add(String reqJson);
    }
    public class ApiServiceImpl implements ApiService {
        private static final Log log = LogFactory.getLog(ApiServiceImpl.class);
        @Autowired
        private UserDao userDao;
        private String token;//供调用rpc校验使用
    
        public String getToken() {
            return token;
        }
    
        public ResponseBean add(String reqJson) {
            ResponseBean responseBean = new ResponseBean(ResponseBean.SUCCESS, "调用成功");
            try {
                Map map = JsonUtil.g.fromJson(reqJson, HashMap.class);
                String username = map.get("username").toString();
                String password = map.get("password").toString();
                String realname = map.get("realname").toString();
                Long userroleid =Double.valueOf(map.get("userroleid").toString()).longValue() ;
                UserBean userBean = new UserBean();
                userBean.setCreatedate(new Date());
                userBean.setPassword(password);
                userBean.setUserroleid(userroleid);
                userBean.setRealname(realname);
                userBean.setUsername(username);
                int count = userDao.add(userBean);
                responseBean.setReturnData(JsonUtil.g.toJson(count));
                responseBean.setReturnCode(10);
            } catch (Exception e) {
                log.error(e.getStackTrace());
                responseBean.setReturnCode(11);
                responseBean.setReturnMsg("服务器异常");
            }
            return responseBean;
        }
    
        public void setToken(String token) {
            this.token = token;//用于设置token(用来验证消费者的token是否是服务器的token)
        }
    }

    2.3:定义http请求的入口,需要3个参数token(进行安全认证)、m(请求方法名)、reqJson(请求的参数)

    @Controller
    @RequestMapping(value = "/api")
    public class ApiController {
        private static final Log log = LogFactory.getLog(ApiController.class);
        @Autowired
        private ApiService apiService;
    
        /**
         * 系统对外公开调用方法
         *
         * @param m       接口方法名
         * @param reqJson 请求参数
         * @param token   请求token
         * @return
         */
        @RequestMapping(value = "/exec", method = RequestMethod.POST)
        @ResponseBody
        public Object exec(@RequestParam(value = "m", required = true) String m,
                           @RequestParam(value = "reqJson", required = true) String reqJson,
                           @RequestParam(value = "token", required = true) String token) {
             log.info(String.format("m=%s,reqJson=%s,token=%s", m, reqJson, token));
            Class c = apiService.getClass();
            Method method = null;
            ResponseBean responseBean = null;
            if (!token.equals(apiService.getToken())) {
                log.error("token校验失败,token=" + token);
                responseBean = new ResponseBean(ResponseBean.FAILURE, "校验失败");
                return responseBean;
            }
            try {
                method = c.getMethod(m, String.class);//利用反射找到对应的方法
            } catch (Exception e) {
                log.error("m参数错误,m=" + m + ";req=" + reqJson, e);
                responseBean = new ResponseBean(ResponseBean.FAILURE, "m参数错误m=" + m);
                return responseBean;
            }
            if (StringUtils.isEmpty(reqJson)) {
                log.error("reqJson为空");
                responseBean = new ResponseBean(ResponseBean.FAILURE, "reqJson为空");
                return responseBean;
            }
            try {
                Object json = method.invoke(apiService, reqJson);
                return json;
            } catch (Exception e) {
                log.error("处理异常,m=" + m + ";req=" + reqJson, e);
                responseBean = new ResponseBean(ResponseBean.FAILURE, "服务器处理异常");
                return responseBean;
            }
        }
    }

    通过上面我们就实现了一个供消费者调用的rest服务。

    3:RPC对rest服务进行包装

    3.1:定义消费者需要的webService

    public interface WebService {
        ResponseBean add(UserBean userBean);
    }

    实现webService

    public class WebserviceImpl implements WebService {
        private final static Log log = LogFactory.getLog(WebserviceImpl.class);
        private String url;//供消费者设置的url地址
        private String token;//供消费者设置的url
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public void setToken(String token) {
            this.token = token;
        }
    
        @Override
        public ResponseBean add(UserBean userBean) {
            Map<String, String> map = new HashMap();
            ResponseBean rb = null;
            map.put("token", token);
            map.put("reqJson", JsonUtil.g.toJson(userBean));
            String reqUrl = url + "?m=add";//在这里进行设置你需要访问哪个方法
            log.debug(reqUrl);
            try {
                String str = HttpClientUtil.executeHttpRequestUTF(reqUrl, map);//访问资源获取返回的json
                log.debug("add return data:" + str);
                rb = JsonUtil.g.fromJson(str, ResponseBean.class);//对json进行转换
                log.debug("getPromInfo return Regions data" + reqUrl);
                return rb;
            } catch (Exception e) {
                rb = new ResponseBean();
                rb.setReturnObject(e);
                log.debug(e.getStackTrace());
                return rb;
            }
        }
    }

    然后对rpc进行打包发布,其他应用程序就可以直接使用了。

    4:配置

    在applicationconfig中加入

    <mvc:annotation-driven/>
    <mvc:default-servlet-handler />
    <mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean否则会出现异常

    <bean id="ApiService" class="com.lp.rpc.impl.ApiServiceImpl">
        <property name="token" value="41729ff3-3406-4fc5-aeca-04f98892999b"></property>
    </bean>
    消费者配置:
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="webService" class="com.lp.rpc.impl.WebserviceImpl">
        <property name="url" value="http://192.168.0.101:8088/api/exec"></property>
        <property name="token" value="41729ff3-3406-4fc5-aeca-04f98892999b"></property>
    </bean>
    </beans>

    5:开启一个项目把rpc项目引进调用

    public class AppMain {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml");
            WebService webService = (WebService) context.getBean("webService");
            UserBean userBean = new UserBean();
            userBean.setUsername("lisi");
            userBean.setPassword("123456");
            userBean.setRealname("李四");
            userBean.setUserroleid(2);
            userBean.setCreatedate(new Date());
            ResponseBean result = webService.add(userBean);
            if (StringUtils.equals(result.getReturnData().toString(),"1")){
                System.out.print("添加成功");
            }
        }
    }

    6:总结

    以上级别能完成不同项目之间的调用了

    优点:简单上手快,可以自己控制,效率也可以。

    缺点:安全性低,需要维护url,有时候别人服务反复开启时候会出现调用不到的情况。

     源码地址

  • 相关阅读:
    Atitit sumdoc everything index tech and index log 目录 1. 使用的tech 1 1.1. Atitit 日志记录的三个trace跟踪等级文件夹级
    Atitit nlp用到的技术与常见类库 目录 1. 常用的技术 1 1.1. 语言处理基础技术 分词 相似度等 1 1.2. 新闻摘要 2 1.3. 情感倾向分析 2 1.4. 文章标签 2 1.
    Atitit 资源类型的分类法规范MIME类型类型 目录 1.1. 一个MIME类型至少包括两个部分:一个类型(type)和一个子类型(subtype)。 1 1.2. 命名格式MIME类型包括一个
    Atitit 六种知识表示法 目录 1. 知识的静态描述和动态描述 1 1.状态空间表示 以状态和运算符(operator) 1 2.问题归约表示(函数式?? 1 (1)一个初始问题描述; 2 (2)
    微信小程序登录流程总结 目录 1.1. 前端调用wx.login 。。给后端传递一个code 1 1.2. 开发者需要在开发者服务器后台调用 auth.code2Session,使用 code 换取
    Atititi 计算机系 教材 目录 1. 硬件类 2 1.1. 《微机系统与接口技术》 2 1.2. 《计算机组成与系统结构(第2版)》 2 2. Atitit 操作系统原理 操作系统原理(cpu
    Atitit 声音和音乐检索 多媒体信息检索 信息检索 目录 1.1. 14.4.5 音频基础知识 1 1.2. 多媒体信息检索的方法主要有哪些?其原理是什么? 1 1.3. 基于文本的检索和基于
    Atitit 信息检索 v3 t55.docx Atitit 现代信息检索 目录 1.1. 信息检索(索引 索引 结构化文本 1 1.2. Atitit 重要章节 1 1.3. 息检索建模 1 1.
    Atiitt 程序语言vm与rt 虚拟机与运行时 目录 1. 运行时 虚拟机的一种,一般指进程级别的虚拟机。 1 1.1. 线程模型 1 1.2. 堆栈机vs 寄存器 1 1.3. 存储模型 2 1
    Atiitt 图像处理的常见功能业务用途与类库与功能实现 目录 1. 常见业务场景 3 1.1. 缩略图 蒙版遮罩挖空 3 1.2. 区域裁剪,水印,旋转 3 1.3. 判断图像大小分辨率要求
  • 原文地址:https://www.cnblogs.com/LipeiNet/p/5862962.html
Copyright © 2011-2022 走看看