前言:现在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,有时候别人服务反复开启时候会出现调用不到的情况。

源码地址

基于Rest服务实现的RPC的更多相关文章

  1. 基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc

    基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc 二月 8, 2016 1 简介 Navi-pbrpc框架是一个高性能的远程调用RPC框架,使用netty4技术提供非阻塞.异步.全 ...

  2. 带你手写基于 Spring 的可插拔式 RPC 框架(一)介绍

    概述 首先这篇文章是要带大家来实现一个框架,听到框架大家可能会觉得非常高大上,其实这和我们平时写业务员代码没什么区别,但是框架是要给别人使用的,所以我们要换位思考,怎么才能让别人用着舒服,怎么样才能让 ...

  3. 基于动态代理的WebAPI/RPC/webSocket框架,一套接口定义,多个通讯方式

    API/RPC/webSocket三个看起来好像没啥相同的地方,在开发时,服务端,客户端实现代码也大不一样 最近整理了一下,通过动态代理的形式,整合了这些开发,都通过统一的接口约束,服务端实现和客户端 ...

  4. 服务治理与RPC · 跬步

    以前写过Django中使用zerorpc的方法,但是由于我们的Django是运行在gevent下,而zeromq需要启动一个后台进程处理消息,与gevent使用的greenlet携程是冲突的. 在Ja ...

  5. 面试都在问的微服务、服务治理、RPC、下一代微服务框架... 一文带你彻底搞懂!

    文章每周持续更新,「三连」让更多人看到是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 单体式应用程序 与微服务相对的另一个概念是传统的单体式应用程序( ...

  6. 面试都在问的「微服务」「RPC」「服务治理」「下一代微服务」一文带你彻底搞懂!

    ❝ 文章每周持续更新,各位的「三连」是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) ❞ 单体式应用程序 与微服务相对的另一个概念是传统的「单体式应用程 ...

  7. 基于Kubernetes服务发现机制的探讨Non Service

    服务注册 注册中⼼作为一般的RPC/Web服务中的底层设施提供了服务进程元数据(IP, Port, Interface, Group,Method等)存储,被Watch的功能,每个服务进程均需接⼊同⼀ ...

  8. Netty(四)基于Netty 的简易版RPC

    3.1 RPC 概述 下面的这张图,大概很多小伙伴都见到过,这是 Dubbo 官网中的一张图描述了项目架构的演进过程 它描述了每一种架构需要的具体配置和组织形态.当网站流量很小时,只需一个应用,将所有 ...

  9. 基于RMI服务传输大文件的完整解决方案

    基于RMI服务传输大文件,分为上传和下载两种操作,需要注意的技术点主要有三方面,第一,RMI服务中传输的数据必须是可序列化的.第二,在传输大文件的过程中应该有进度提醒机制,对于大文件传输来说,这点很重 ...

随机推荐

  1. step by step 之餐饮管理系统七(点菜模块实现)

    好长时间没有更新这个系列了,一是因为这段时间比较忙,有很多事情,二来要学习新的东西,AngularJs,devExpress这两上框架,都是比较有名的框架,先上图: 上面就是用来点菜的界面,左边是已点 ...

  2. Lisp 函数

    (quote x) [返回x] >>>>>>>>>>>>>>>>>>>>> ...

  3. iOS 选择的照片或者拍照的图片上添加日期水印

    1..引入框架 #import "CLLocation+GPSDictionary.h"#import "NSDictionary+CLLocation.h" ...

  4. linux下的5个查找命令

    在Linux中,有很多方法可以做到这一点.国外网站LinuxHaxor总结了五条命令,你可以看看自己知道几条.大多数程序员,可能经常使用其中的2到3条,对这5条命令都很熟悉的人应该是不多的. 1. f ...

  5. No operation was found with the name {http://impl.service.xq.com/}sayHi

    org.apache.cxf.common.i18n.UncheckedException: No operation was found with the name {http://impl.ser ...

  6. C#多线程学习

    一.线程的定义 进程(Process)是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程 ...

  7. unity 计时器

    2017年1月3号,周二,晴. //设置时间 float tempTime = 5; void OnGUI(){ //设置显示 GUI.Label (new Rect(100,100,100,100) ...

  8. iptables Data filtering详解

    内容简介防火墙的概述iptables简介iptables基础iptables语法iptables实例案例详解(一)防火墙的简介防火墙是指设置在不同网络或网络安全域之间的一系列部件的组合,它能增强机构内 ...

  9. IOS 计时器暂停和开始 防止重复点击

    -(IBAction)btnClick{ [self starTimer];//开始计时 //[self stopTimer]; } -(NSTimer*)timer{ if (!_timer) { ...

  10. ado.net 向sql中插入新数据的同时获取自增重的id值

    两种方法都可以实现: 要获取的自增长列为phonebookID 方法一: sql = "insert into phonebook (mobile,peoplename) output in ...