基于jsonrpc4j实现JSON-RPC over HTTP(客户端多种调用方式)
  GvKa0siuaY4Z 2023年12月22日 44 0


1.说明

前文基于jsonrpc4j实现JSON-RPC over HTTP(服务端集成Spring Boot),
介绍了JSON-RPC over HTTP服务端的实现方法,
并且通过Postman工具调用服务端对外提供的方法,
下面介绍两种基于Java代码调用客户端的方法:

  • 非Spring框架的客户端调用方法
  • 基于Spring框架的客户端调用方法

基于之前服务端的代码开发示例,
下面详细介绍这两种方法的实现。

2.非Spring框架的客户端

不依赖Spring框架的客户端,
实现SON-RPC over HTTP的RPC调用,
只需要依赖jsonrpc4j框架即可:

<dependency>
                <groupId>com.github.briandilley.jsonrpc4j</groupId>
                <artifactId>jsonrpc4j</artifactId>
                <version>1.6</version>
            </dependency>

新建客户端测试类JsonRpcClientTest.java如下:

package com.ai.json.rpc.client;

import java.net.URL;

import org.junit.jupiter.api.Test;

import com.ai.json.rpc.entity.Book;
import com.ai.json.rpc.service.BookRpcService;
import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
import com.googlecode.jsonrpc4j.ProxyUtil;

/**
 * 测试JSON-RPC over HTTP调用,客户端不依赖Spring Boot,服务端依赖Spring Boot
 *
 */
public class JsonRpcClientTest {
    /**
     * 基于方法名称的客户端调用
     */
    @Test
    public void testClint2Server() throws Throwable {
        URL url = new URL("http://localhost:9090/rpc/books");

        JsonRpcHttpClient client = new JsonRpcHttpClient(url);

        // 调用JSON RPC服务下的findById方法
        Book book = client.invoke("findById", new Object[] { "1" }, Book.class);
        System.out.println(book);

    }

    /**
     * 基于API的客户端调用,需要支持JSON-RPC over HTTP
     */
    @Test
    public void testApi2Server() throws Throwable {
        URL url = new URL("http://localhost:9090/rpc/books");

        JsonRpcHttpClient client = new JsonRpcHttpClient(url);

        // 创建客户端的JSON RPC服务的代理类
        BookRpcService bookRpcService = ProxyUtil.createClientProxy(getClass().getClassLoader(), BookRpcService.class,
                client);

        // 基于API调用findById方法
        Book book = bookRpcService.findById("2");
        System.out.println(book);
    }
}

这里通过JsonRpcHttpClient调用JSON-RPC对外提供的方法:
http://localhost:9090/rpc/books 可以直接通过JsonRpcHttpClient的invoke方法调用,
也可以通过ProxyUtil创建代理类,
通过接口API的方式优雅的调用RPC方法。

3.基于Spring框架的客户端

新建子工程JSON-RPC-SB-client,
pom增加依赖管理如下:

<dependencies>
        <dependency>
            <groupId>edu.yuwen.protocol</groupId>
            <artifactId>JSON-RPC-SB-api</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

新建启动类JsonRpcClientApplication.java:

package com.ai.json.rpc.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JsonRpcClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(JsonRpcClientApplication.class, args);
    }
}

新建配置类RpcConfiguration.java:

package com.ai.json.rpc.client.config;

import java.net.URL;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.googlecode.jsonrpc4j.spring.AutoJsonRpcClientProxyCreator;

@Configuration
public class RpcConfiguration {

    private static Logger LOG = LoggerFactory.getLogger(RpcConfiguration.class);

    @Bean
    public AutoJsonRpcClientProxyCreator rpcClientProxyCreator(@Value("${rpc.client.serverUrl}") String url,
            @Value("${rpc.client.basePackage}") String basePackage) {

        LOG.info("配置远程服务端的URL={}, 本地扫描包路径basePackage={}", url, basePackage);
        AutoJsonRpcClientProxyCreator clientProxyCreator = new AutoJsonRpcClientProxyCreator();
        try {
            clientProxyCreator.setBaseUrl(new URL(url));
            clientProxyCreator.setContentType("application/json");
        } catch (Exception e) {
            LOG.error("配置AutoJsonRpcClientProxyCreator发生异常=", e);
        }

        clientProxyCreator.setScanPackage(basePackage);
        return clientProxyCreator;
    }
}

新建配置文件application.yml:

server:
  port: 9091
  
rpc:
  client:
    serverUrl: http://localhost:9090
    basePackage: com.ai.json.rpc.service

注意这里依赖了JSON-RPC-SB-api模块,
涉及到的关键代码如下:

package com.ai.json.rpc.service;

import com.ai.json.rpc.entity.Book;
import com.googlecode.jsonrpc4j.JsonRpcService;

@JsonRpcService("rpc/books")
public interface BookRpcService {
    public Book findById(String id);
}

4.基于Spring框架的客户端测试

新建测试类JsonRpcContainerTest.java:

package com.ai.json.rpc.client;

import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.ai.json.rpc.entity.Book;
import com.ai.json.rpc.service.BookRpcService;

/**
 * 测试JSON-RPC over HTTP调用,客户端和服务端都依赖Spring Boot容器
 *
 */
@SpringBootTest
public class JsonRpcContainerTest {
    private static Logger LOG = LoggerFactory.getLogger(JsonRpcContainerTest.class);

    /**
     * Spring容器注入的rpc服务中已经设置好了远端服务URL
     */
    @Autowired
    private BookRpcService bookRpcService;

    @Test
    public void queryBooks() {
        LOG.info("客户端开始自动查询图书");

        for (int i = 1; i <= 3; i++) {
            String id = String.valueOf(i);
            Book book = bookRpcService.findById(id);
            LOG.info("根据图书Id={}找到图书Book={}", id, book);
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                LOG.error("自动查询图书发生异常=", e);
            }
        }
    }
}

通过@SpringBootTest注解启动容器,
可以获得代理过后的BookRpcService实例,
直接调用接口的API即可实现RPC调用。

5.基于Spring框架的客户端使用

类似于上面的测试类,
在业务代码中使用JSON-RPC over HTTP 接口时,
直接注入BookRpcService即可使用,
运行JsonRpcClientApplication启动类后,
会自动注入实际的动态代理类。

新建业务类AutoQueryBookService.java:

package com.ai.json.rpc.client.auto;

import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.ai.json.rpc.entity.Book;
import com.ai.json.rpc.service.BookRpcService;

@Component
public class AutoQueryBookService {
    private static Logger LOG = LoggerFactory.getLogger(AutoQueryBookService.class);

    /**
     * Spring容器注入的rpc服务中已经设置好了远端服务URL
     */
    @Autowired
    private BookRpcService bookRpcService;

    @PostConstruct
    public void queryBooks() {
        LOG.info("客户端开始自动查询图书");

        for (int i = 1; i <= 3; i++) {
            String id = String.valueOf(i);
            Book book = bookRpcService.findById(id);
            LOG.info("根据图书Id={}找到图书Book={}", id, book);
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                LOG.error("自动查询图书发生异常=", e);
            }
        }

    }
}

这里通过@PostConstruct注解,
实现了再容器启动后,
在容器注入BookRpcService实例后,
自动开始执行查询图书的操作,
运行日志如下:

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.1.RELEASE)

2023-12-11 15:58:24.045  INFO 13568 --- [           main] c.a.j.r.client.JsonRpcClientApplication  : Starting JsonRpcClientApplication on yuwen-asiainfo with PID 13568 (D:\Code\Learn\protocol-impl\RPC-impl\JSON-RPC-impl\JSON-RPC-SpringBoot\JSON-RPC-SB-client\target\classes started by yuwen in D:\Code\Learn\protocol-impl\RPC-impl\JSON-RPC-impl\JSON-RPC-SpringBoot\JSON-RPC-SB-client)
2023-12-11 15:58:24.047  INFO 13568 --- [           main] c.a.j.r.client.JsonRpcClientApplication  : No active profile set, falling back to default profiles: default
2023-12-11 15:58:24.546  INFO 13568 --- [           main] o.s.c.a.ConfigurationClassEnhancer       : @Bean method RpcConfiguration.rpcClientProxyCreator is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
2023-12-11 15:58:24.552  INFO 13568 --- [           main] c.a.j.r.client.config.RpcConfiguration   : 配置远程服务端的URL=http://localhost:9090, 本地扫描包路径basePackage=com.ai.json.rpc.service
2023-12-11 15:58:25.062  INFO 13568 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9091 (http)
2023-12-11 15:58:25.071  INFO 13568 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-12-11 15:58:25.071  INFO 13568 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.36]
2023-12-11 15:58:25.134  INFO 13568 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-12-11 15:58:25.134  INFO 13568 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1054 ms
2023-12-11 15:58:25.170  INFO 13568 --- [           main] c.a.j.r.c.auto.AutoQueryBookService      : 客户端开始自动查询图书
2023-12-11 15:58:25.358  INFO 13568 --- [           main] c.a.j.r.c.auto.AutoQueryBookService      : 根据图书Id=1找到图书Book=Book [id=1, name=Java核心技术, price=199]
2023-12-11 15:58:35.362  INFO 13568 --- [           main] c.a.j.r.c.auto.AutoQueryBookService      : 根据图书Id=2找到图书Book=Book [id=2, name=人月神话, price=58]
2023-12-11 15:58:45.365  INFO 13568 --- [           main] c.a.j.r.c.auto.AutoQueryBookService      : 根据图书Id=3找到图书Book=Book [id=3, name=程序员养生指南, price=996]
2023-12-11 15:58:55.411  INFO 13568 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2023-12-11 15:58:55.518  INFO 13568 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9091 (http) with context path ''
2023-12-11 15:58:55.524  INFO 13568 --- [           main] c.a.j.r.client.JsonRpcClientApplication  : Started JsonRpcClientApplication in 31.81 seconds (JVM running for 32.165)


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月22日 0

暂无评论

推荐阅读
  SuVXIKXQi51s   2023年12月23日   73   0   0 pythonHTTPHTTPPython
GvKa0siuaY4Z