前言:现在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. Tomcat部署遇到的问题

    项目服务端:Tomcat6.0.41 选用数据库:Mysql5.6.17 JDK环境:1.6.37 运行系统:Windows server 2008(64bit) ================== ...

  2. Python基于pandas的数据处理(二)

    14 抽样 df.sample(10, replace = True) df.sample(3) df.sample(frac = 0.5) # 按比例抽样 df.sample(frac = 10, ...

  3. [java基础知识]java安装步骤

    jre:  java运行环境.  jre =  java虚拟机 + 核心类库(辅助java虚拟机运行的文件).如果只是运行java程序,只需要安装jre.    jdk: java开发工具集   jd ...

  4. install skype4.3 in ubuntu15.04

    Canonical Partners repository finally adds support for Ubuntu 15.04. Here’s how to enable the reposi ...

  5. 今天自己解决了两个问题(IE10 type slow ChromeDriver erro)

    都是通过google解决的,其实本应该很快解决,可是因自己粗心,大写小错了,加上java基础不过关, "webdriver.chrome.driver"中的webdriver应是全 ...

  6. MVVM框架中的一个非常重要的内容:数据双向绑定

    双向绑定的意思就是,如下图中,当在input框中输入字符时,红色框框中的字也会随之改变. input框中需要一个绑定:ms-duplex(即“双工绑定”),http://avalonjs.github ...

  7. Perl的多进程框架(watcher-worker)

    关于perl的多进程,大家可能马上会想到Parallel::ForkManager这个模块.但是今天我们试着自己动手写一个类似的框架:) 该多进程开发模型从开源服务器框架Lighttpd发展而来,核心 ...

  8. 《Learninghard C#学习笔记》回馈网友,免费送书5本

    前言: 在博客园园友的大力支持下,本人的第一本书<Learninghard C#学习笔记>终于出版了. 这本书是本人学习C#的亲身经历,书籍内容都是本人学习过程中认为必须掌握的内容,完全无 ...

  9. 图解,为多个oracle数据库下添加ArcSde实例

    最开始肯定要先建一个oracle数据库,我假设名称为dbgis 1, 2, 3, 不重新指定就会出现这个错误,因为以前有sde.dbf文件了 4, 5, 6, 7, 8, 如果以前授权成功过就会出现这 ...

  10. SWT:获取字符串实际宽度

    由于SWT取用的是系统文字size,有个简单方式可以获取一整段包含中文\英文\数字\特殊字符的字符串宽度. 即是利用Label的computeSize方法,我们知道Label的大小可以随着内容文字伸缩 ...