前言:现在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. 「2014-2-23」Note on Preliminary Introduction to Distributed System

    今天读了几篇分布式相关的内容,记录一下.非经典论文,非系统化阅读,非严谨思考和总结.主要的着眼点在于分布式存储:好处是,跨越单台物理机器的计算和存储能力的限制,防止单点故障(single point ...

  2. Proximal Gradient Descent for L1 Regularization

    [本文链接:http://www.cnblogs.com/breezedeus/p/3426757.html,转载请注明出处] 假设我们要求解以下的最小化问题:                     ...

  3. If you really want to compile without asm, configure with --disable-asm.

    真是一个奇葩问题,对我来说是的,完全不知道是什么意思,但是他就是出现了. 找到了一个相关问题http://trac.ffmpeg.org/wiki/How%20to%20quickly%20compi ...

  4. 用sql取出来的list需要处理成map的两种情况

    1. 原生sql: select a.id,a.name from a SQLQuery sqlQuery=this.getSession().createSQLQuery(sb.toString() ...

  5. Python学习之路—Day1

    第1章 Python语言简介 1.1 Python是什么 Python(英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn)是什么呢?简单的说,它是一种计算机编程语言及一组配套的软件工具和库. ...

  6. C++ std::map::erase用法及其陷阱

    1.引入: STL的map中有一个erase方法用来从一个map中删除制定的节点 eg: map<string,string> mapTest; typedef map<string ...

  7. linux系统添加硬盘方法

    [root@wen /]# fdisk -l[root@wen /]# fdisk /dev/sdb[root@wen /]# mkfs -t ext3 -c /dev/sdb1[root@wen / ...

  8. jQuery+ASP.NET MVC基于CORS实现带cookie的跨域ajax请求

    这是今天遇到的一个实际问题,在这篇随笔中记录一下解决方法. ASP.NET Web API提供了CORS支持,但ASP.NET MVC默认不支持,需要自己动手实现.可以写一个用于实现CORS的Acti ...

  9. Sql Server tempdb原理-缓存机制解析实践

    Tempdb就像Sqlserver的临时仓库,各式各样的对象,数据在里面进行频繁计算,操作.大量的操作使得tempdb可能面临很大压力,tempdb中缓存的设计就是为了缓解这些压力.这次就为大家介绍下 ...

  10. AJAX原理总结

    AJAX全称 Asynchronous JavaScript and XML(异步的JavaScript 和XML) 同步和异步 异步传输是面向字符的传输,单位是字符 同步传输是面向比特,单位是帧,传 ...