RPC实践(二)JsonRPC实践

5 篇文章 1 订阅

一、JsonRPC介绍

json-rpc是基于json的跨语言远程调用协议,比xml-rpc、webservice等基于文本的协议传输数据格小;相对hessian、Java-rpc等二进制协议便于调试、实现、扩展,是非常优秀的一种远程调用协议。目前主流语言都已有json-rpc的实现框架,java语言中较好的json-rpc实现框架有jsonrpc4j、jpoxy、json-rpc。三者之中jsonrpc4j既可独立使用,又可与spring无缝集合,比较适合于基于spring的项目开发。


二、JsonRPC简单说明

1、调用的Json格式

     向服务端传输数据格式如下:
   { "method": "方法名", "params": [“参数数组”], "id":  方法ID}

     说明:

    第一个参数: 是方法的名值对

    第二个参数: 是参数数组

    第三个参数: 是方法ID(可以随意填)

   举例:  { "method": "doSomething", "params": [], "id": 1234}

   doSomething 是远程对象的方法, []  表示参数为空

2、输出的Json格式

{
  "jsonrpc": "2.0",
  "id": "1234",
  "result": null
}


三、JsonRPC的demo

下面展示一个demo,这个demo的主要内容,就是创建一个服务端对象,由客户端进行调用

对象关系

对象关系图如下:


3.1工程搭建

1) 创建一个web projcct工程

2) 创建相应的class,拷贝lib中需要的jar包


3)发布,并运行tomcat

发布myeclipse的tomcat环境,最重要的是web.xml文件,下面展现web.xml的内容


 注意: 最后的url,在  "主机:端口"后跟的工程名称,然后是url-pattern

以上图为例: http://127.0.0.1:8080/StudyJsonrpc4j/rpc


3.2代码

1) 实体类

HelloWorldService.java

package com.cwqsolo.demo.enitity;

/*
 * 定义一个服务的接口
 */
public interface HelloWorldService {
    
    public HelloWorldBean getDemoBean(String code, String msg);

    public Integer getInt(Integer code);

    public String getString(String msg);

    public void doSomething();

}

HelloWorldBean.java

package com.cwqsolo.demo.enitity;

import java.io.Serializable;

public class HelloWorldBean implements Serializable{
    
    private static final long serialVersionUID = -12345L;
    private int code;
    private String msg;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
HelloWorldServiceImpl.java
package com.cwqsolo.demo.enitity;

public class HelloWorldServiceImpl  implements HelloWorldService {
    
    int  count=0;
    
    public HelloWorldBean getDemoBean(String code, String msg) {
    	
    	System.out.println("HelloWorldBean get");
    	
    	HelloWorldBean bean1 = new HelloWorldBean();
        bean1.setCode(Integer.parseInt(code));
        bean1.setMsg(msg+",javaBean is fine!");
        return bean1;
    }

    //计算服务端count值与客户端传进来的code值的和
    public Integer getInt(Integer code) {
        return code+count;
    }

    //返回某种字符串操作的结果
    public String getString(String msg) {
        return msg+",server is fine!";
    }

    //服务端接受调用,执行某些业务动作。这里是count进行技术
    public void doSomething() {
	    count++;
        System.out.println("do something"+"; count=>"+count);
    } 

}
2) 服务端代码

JsonRpcService.java

package com.cwqsolo.demo.server;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.cwqsolo.demo.enitity.HelloWorldService;
import com.cwqsolo.demo.enitity.HelloWorldServiceImpl;
import com.googlecode.jsonrpc4j.JsonRpcServer;



public class JsonRpcService  extends HttpServlet {
	
    private static final long serialVersionUID = 1L;
    private JsonRpcServer rpcServer = null;

    public JsonRpcService() {
        super();
        
        //服务端生成HelloWorldServiceImpl对象,并且提供对应的方法
        rpcServer = new JsonRpcServer(new HelloWorldServiceImpl(), HelloWorldService.class );
    }

    @Override
    protected void service(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
    	System.out.println("JsonRpcService service being call");
        rpcServer.handle(request, response);
    }

}



3) 客户端代码

package com.cwqsolo.demo.client;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import com.cwqsolo.demo.enitity.HelloWorldBean;
import com.googlecode.jsonrpc4j.JsonRpcHttpClient;

public class JsonRpcClient{
    
    static JsonRpcHttpClient client;

    public JsonRpcClient() {

    }

    public static void main(String[] args) throws Throwable {
	
        // 实例化请求地址,注意服务端web.xml中地址的配置
        try {
            client = new JsonRpcHttpClient(new URL(
                    "http://127.0.0.1:8080/StudyJsonrpc4j/rpc"));
            
            // 请求头中添加的信息,这里可以自己定义
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("Name", "Key");
            
            // 添加到请求头中去
            client.setHeaders(headers);
            
            //客户端doSomethine方法,通过调用远程对象的dosomething
            JsonRpcClient test = new JsonRpcClient();

            
            //客户端getDemo,是获取远程对象的HelloWorldBean
            HelloWorldBean demo = test.getDemo(1, "Hello");       
            //执行远程对象的get方法
            System.out.println("++++++ call remote javabean obj function ++++++");
            System.out.println(demo.getCode());
            System.out.println(demo.getMsg());          
                       
                       
            //执行远程对象的方法
            int code = test.getInt(10);
            System.out.println("++++++ call remote function Integer:first ++++++");
            System.out.println(code);
            
            //调用服务端doSomething 方法
            test.doSomething();
            
            //第二次调用远程对象的getInt方法
            code = test.getInt(10);
            System.out.println("++++++ call remote function Integer:second ++++++");
            System.out.println(code);
            
            
            String msg = test.getString("hello");
            System.out.println("++++++ Call remote function String  ++++++");
            System.out.println(msg);
            System.out.println("++++++ end ++++++");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     *客户端dosomething 方法,调用服务端的dosomething
     */
    public void doSomething() throws Throwable {
        client.invoke("doSomething", null);
    }

    /*
     *客户端getDemo 方法,调用服务端的getDemo
     */
    public HelloWorldBean getDemo(int code, String msg) throws Throwable {
        String[] params = new String[] { String.valueOf(code), msg };
        HelloWorldBean demo = null;
        demo = client.invoke("getDemoBean", params, HelloWorldBean.class);
        return demo;
    }

    /*
     * 客户端getInt 是调用服务端getInt方法
     */
    public int getInt(int code) throws Throwable {
        Integer[] codes = new Integer[] { code };
        return client.invoke("getInt", codes, Integer.class);
    }

    /*
     * 客户端getString 是调用服务端getString方法
     */
    public String getString(String msg) throws Throwable {
        String[] msgs = new String[] { msg };
        return client.invoke("getString", msgs, String.class);
    }

}

3.3运行和测试:

1) 服务端启动:

在myeclipse的环境下,启动server

信息: Starting Servlet Engine: Apache Tomcat/7.0.30
十二月 12, 2016 4:49:56 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deploying web application directory E:\cwqwork\MyEclipse_Workspace\.metadata\.me_tcat7\webapps\StudyJsonrpc4j
十二月 12, 2016 4:49:58 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-bio-8080"]
十二月 12, 2016 4:49:58 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["ajp-bio-8009"]
十二月 12, 2016 4:49:58 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 2340 ms
可以看到打印出来的日志:

信息: Deploying web application directory E:\cwqwork\MyEclipse_Workspace\.metadata\.me_tcat7\webapps\StudyJsonrpc4j  ---表示发布在tomcat环境的工程,在tomcat启动后加载

 Server startup in 2340 ms  ----表示tomcat启动成功

2) 客户端程序调用

直接运行客户端程序进行调用,在客户端代码类,右键运行:

++++++ call remote javabean obj function ++++++
1
Hello,javaBean is fine!
++++++ call remote function Integer:first ++++++
10
++++++ call remote function Integer:second ++++++
11
++++++ Call remote function String  ++++++
hello,server is fine!
++++++ end ++++++

可以看到 first,second调用,返回的结果不同,说明服务端的数据在第一次调用后,数据发生了改写


3)直接浏览器中get方式调用,以代码用doSomething 方法为例

http://127.0.0.1:8080/StudyJsonrpc4j/rpc?method=doSomething&id=1234&params=JTViJTVk

说明:params=JTViJTVk, 因为params 参数为空,填入的[],需要转换为 url编码,再转为base64编码,这个编码为 JTViJTVk

调用后,客户端会提示下载,下载后用浏览器打开,里面是调用返回的内容


服务端打印

JsonRpcService service being call
do something; count=>3

4) 可以用postman 工具来测试,用get方法,post方法都能成功

用get方法:


在第一个红框处输入: http://127.0.0.1:8080/StudyJsonrpc4j/rpc?method=doSomething&id=1234&params=JTViJTVk

第二个红框是send 后,返回的内容


用post 方法:


用POST方式,url 为:http://127.0.0.1:8080/StudyJsonrpc4j/rpc, 点击params 按钮后,在body里面,填入json串

 { "method": "doSomething", "params": [], "id": 1234}

点send 按钮后,在返回区可以看到返回内容
















  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
拍拍贷微服务rpc框架源码.zip # 拍拍贷微服务体系 拍拍贷微服务体系是拍拍贷基础框架部总结内部微服务多年实践,参考、吸收大量业内解决方案形成的适合中型互联网公司的微服务解决方案。 拍拍贷微服务体系主要组成部分: - Raptor rpc框架。 - Radar服务注册中心。 - Kong网关。 微服务实例启动之后,会自动注册到radar服务注册中心,实例启动正常后,kong网关周期性的将实例信息同步到kong的插件配置。微服务之间的调用、zuul网关调用微服务,都是通过域名进行调用,域名解析到kong网关。Kong网关根据域名和微服务的对应关系,对微服务实例进行负载均衡运算后,得到一个实例,最终进行调用。 拍拍贷微服务体系主要架构考虑: - 由Kong网关形成的集中式服务治理。降低由于客户端服务治理bugfix等引起的升级成本。 - 采用HTTP 1.1作为底层传输协议,从外部到内部无需进行协议转换。 - 采用HTTP 1.1 作为底层传输协议,不会引起原有基于HTTP协议的已有设施失效。 # Raptor微服务rpc组件 Raptor微服务rpc组件是拍拍贷基础框架部参考、借鉴了大量已有rpc框架、rpc组件的设计,研发的一款基于google protobuf的轻量级,可扩展的rpc组件。 **Raptor设计理念:** - 微内核。Raptor核心实现raptor rpc必须的服务定义、protobuf序列化/反序列化、扩展接口和最小化实现。 - 可扩展。Raptor核心预留了Client、Endpoint等可扩展接口,提供相应的实现即可替换掉默认的实现。 - 模块化。Raptor核心不提供组装能力,raptor核心提供了rpc框架所需的核心组件,由外部框架进行组装。例如,raptor默认实现提供了基于spring-boot的组装方式。 **Raptor的价值:** - 契约驱动开发模式,以protobuf为契约,帮助企业规模化生产。 - JAVA语言开发,工程性好,保护原有技术投资。 - 预留兼容性,以protobuf为契约,符合社区技术趋势,为后续以protobuf为基础做技术升级留下兼容性。例如,引入grpc,业务契约无需改变。 - 灵活性,可采用集中治理,也可以采用客户端治理;可使用protobuf binary over HTTP也可以使用protobuf json over HTTP,服务提供方根据HTTP头自适应;为架构师留下灵活的选择余地。
rest_rpc 是一个 C++ 的 RPC 框架,它支持 JSON 作为数据传输格式。在使用 rest_rpc 进行 JSON 解析时,可以使用第三方库 jsoncpp。 以下是在 rest_rpc 中解析 JSON 的步骤: 1. 引入 jsoncpp 库:在 CMakeLists.txt 中添加 jsoncpp 库的链接; 2. 定义 JSON 字符串:将 JSON 字符串作为参数传递给 rest_rpc 的远程调用函数; 3. 解析 JSON:使用 jsoncpp 库的解析函数将 JSON 字符串解析为 jsoncpp::Value 类型的对象,然后使用该对象进行数据的读取和操作。 以下是一个简单的示例代码,演示了如何在 rest_rpc 中解析 JSON: ```c++ #include <iostream> #include <rest_rpc/client.hpp> #include <json/json.h> using namespace rest_rpc; using namespace rpc_service; using namespace std; int main() { // 连接远端服务 client c("127.0.0.1", 9000); // 定义 JSON 字符串 string json_str = "{\"name\":\"Tom\", \"age\":20}"; // 解析 JSON Json::Value root; Json::Reader reader; bool parsing_successful = reader.parse(json_str, root); if (!parsing_successful) { cerr << "Failed to parse JSON string: " << json_str << endl; return -1; } // 读取 JSON 数据 string name = root["name"].asString(); int age = root["age"].asInt(); // 调用远端服务并传递 JSON 数据 int result = c.call<int>("add", name, age); cout << "The result is " << result << endl; return 0; } ``` 在以上代码中,我们使用了 jsoncpp 库中的 Json::Reader 类和 Json::Value 类来解析 JSON 字符串。首先,我们将 JSON 字符串传递给 Json::Reader 的 parse 函数进行解析,如果解析成功,则 Json::Value 类型的 root 对象中包含了 JSON 数据。然后,我们使用 root 对象中的 asString 和 asInt 函数来读取 JSON 数据,并将其作为参数传递给远端服务的 add 函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值