Spring原生Rpc六种的正确打开方式实现示例

目录
  • 前言
  • 什么是Rpc?
  • Spring中的Rpc
  • 定义服务接口
  • 调用服务代码
  • WEBSERVICE的RPC实现
    • 服务提供者
      • 服务实现
      • 服务暴露
    • 服务消费者
  • HTTP的RPC实现
    • 服务提供者
      • 服务实现
      • 服务暴露
    • 服务消费者
  • 文末结语

前言

在java生态圈谈到Rpc,很多人可能就会想到Dubbo、Motan、Grpc等框架。但是你知道吗?作为Java编程全家桶的Spring已经内置了多种RPC的实现方式,可以直接使用。存在即合理,有些场景下其实并不需要Dubbo,Grpc等重量级的RPC组件,那么Spring的轻量封装就可以派上用场了。下面就来探索下Spring中的RPC的实现方式以及如何使用的。

文中代码地址:https://gitee.com/kailing/spring-rpc

什么是Rpc?

Rpc(Remote Procedure Call): 封装了内部实现的远程调用过程就是rpc,rpc主要为了简化远程服务调用,通俗的讲就是调用远程服务(跨主机,跨进程)就像调用本地方法一样。Spring Cloud体系中的Fegin 技术也可以认为是采用http协议传输数据的一种Rpc技术。

Spring中的Rpc

Spring中内置了六种不同数据传输方式的原生的Rpc实现,分别是WebService、Jms、Rmi、Http、Hessian(http)、Amqp。熟悉Rpc的知道,在Java中,主要是通过生成服务接口的代理来实现Rpc服务的调用,Dubbo、Motan这样,Spring的实现也是这样。在Rpc服务调用中,有两个角色,分别是服务的提供者和调用者(消费者)。一方面服务调用者通过代理,在服务调用时会传输服务定义的接口名+方法参数给到提供者。另一方面服务提供者拿到接口信息找到本地服务生成调用结果返回给调用者。所以下面所述六种Rpc实现都会有一个公共的服务接口定义,以及各自的代理实现配置。

定义服务接口

/**
 * @WebService 注解只用于ws 提供的RPC服务
 */ @WebService public interface AccountService { Account getAccount(String name);

     class Account implements Serializable { private String name; public String getName(){ return name;
          } public void setName(String name) { this.name = name;
          }
     }
}

公共的api,在Rpc的提供者和消费者中都会使用到,提供者中会实现这个接口提供服务,消费者会通过代理,生成这个接口的代理实现 ,然后通过底层封装发送具体的消息。和使用dubbo和motan类似

调用服务代码

@SpringBootApplication public class WsConsumerApplication { @Autowired private AccountService accountService; @PostConstruct public void callRpcService(){
		System.out.println("RPC远程访问开始!");
		System.err.println(accountService.getAccount("kl").getName());
		System.out.println("RPC远程访问结束!");
	} public static void main(String[] args) {
		SpringApplication.run(WsConsumerApplication.class, args);
	}
}

每个Rpc实现都一样,都是通过注入AccountService 接口的代理实现来调用服务。不过每个Rpc的代理的配置方式会略有不同,主要体现在不同的传输技术会用到不同的配置。总的来说,连接url(http://127.0.0.1、tcp://172.0.0.1、rmi://127.0.0.1),端口、代理接口信息等都是共同需要的。

WEBSERVICE的RPC实现

服务提供者

服务实现

@WebService(serviceName="AccountService",endpointInterface = "com.spring.rpc.api.AccountService") @Service public class AccountServiceImpl extends SpringBeanAutowiringSupport implements AccountService { Logger logger = LoggerFactory.getLogger(getClass()); @Override @WebMethod public Account getAccount(String name) {
        logger.info("{} 请求获取账号!", name);
        Account account = new Account();
        account.setName(name + "的账号"); return account;
    }
}

和其他服务实现不一样,WebService定义服务时,需要使用@WebService和@WebMethod注解标记

服务暴露

@Configuration public class WsConfig { private String ipList = "127.0.0.1"; private String userName = "admin"; private String passWord = "sasa"; @Bean public SimpleHttpServerJaxWsServiceExporter rmiServiceExporter(Authenticator authenticator) {
        SimpleHttpServerJaxWsServiceExporter exporter = new SimpleHttpServerJaxWsServiceExporter();
        exporter.setHostname("127.0.0.1");
        exporter.setPort(8083);
        exporter.setAuthenticator(authenticator); return exporter;
    } @Bean public Authenticator authenticator(){
        Authenticator authenticator = new Authenticator();
        authenticator.setIpList(ipList);
        authenticator.setUserName(userName);
        authenticator.setPassWord(passWord); return authenticator;
    }
}

完成如上代码,其实我们已经构建了一个完整的WebService服务,而且还加上了用户、密码和ip白名单等接口权限认证,访问:http://127.0.0.1:8083/AccountServiceImpl?WSDL 就可以看到服务的定义,如下:

服务消费者

@Configuration public class WsConfig { @Bean("accountService") public JaxWsPortProxyFactoryBean accountService()throws Exception{
        JaxWsPortProxyFactoryBean factoryBean = new JaxWsPortProxyFactoryBean();
        factoryBean.setServiceName("AccountService");
        factoryBean.setPortName("AccountServiceImplPort");
        factoryBean.setNamespaceUri("http://provider.ws.rpc.spring.com/");
        URL wsdlDocumentUrl = new URL("http://127.0.0.1:8083/AccountServiceImpl?WSDL");
        factoryBean.setWsdlDocumentUrl(wsdlDocumentUrl);
        factoryBean.setServiceInterface(AccountService.class);
        factoryBean.setUsername("admin");
        factoryBean.setPassword("sasa"); return factoryBean;
    }
}

通过声明JaxWsPortProxyFactoryBean来获得AccountService.class的代理实例。当注入服务调用方法时,实际上是触发了一次WebService的远程调用

HTTP的RPC实现

服务提供者

服务实现

@Service public class AccountServiceImpl implements AccountService { Logger logger = LoggerFactory.getLogger(getClass()); @Override public Account getAccount(String name) {
        logger.info("{} 请求获取账号!", name);
        Account account = new Account();
        account.setName(name + "的账号"); return account;
    }
}

服务暴露

@Configuration public class HttpConfig { @Bean("/AccountService") public HttpInvokerServiceExporter rmiServiceExporter(AccountServiceImpl accountService){
        HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter();
        exporter.setService(accountService);
        exporter.setServiceInterface(AccountService.class); return exporter;
    } @Bean public ServletRegistrationBean servletRegistrationBean(DispatcherServlet dispatcherServlet) {
        ServletRegistrationBean servlet = new ServletRegistrationBean();
        servlet.setServlet(dispatcherServlet);
        servlet.setName("remoting");
        servlet.setLoadOnStartup(1);
        servlet.addUrlMappings("/remoting/*"); return servlet;
    }
}

服务消费者

@Configuration public class HttpConfig { @Bean("accountService") public HttpInvokerProxyFactoryBean accountService(){
        HttpInvokerProxyFactoryBean factoryBean = new HttpInvokerProxyFactoryBean();
        factoryBean.setHttpInvokerRequestExecutor(new HttpComponentsHttpInvokerRequestExecutor());
        factoryBean.setServiceUrl("http://127.0.0.1:8081/remoting/AccountService");
        factoryBean.setServiceInterface(AccountService.class); return factoryBean;
    }
}

可以看到,在配置Http实现的Rpc服务消费者时,和WebService是类似的,定义一个FactoryBean就ok了。其实其他的四种Rpc实现也都大同小异。后面就不一一列举了

文末结语

博文起草构思的时候本来打算将Spring中内置六种Rpc实现都详细描述下,后面看着看着就觉得使用起来真的很类似。只不过像Amqp和Jms以及WebService等实现需要有这方面技术经验的人才能看的明白。但单就Rpc使用和实现来说基本差不多,所以后面就没有一一列出占用篇幅。但是上面提到的WebService、Jms、Rmi、Http、Hessian、Amqp这六种实现在上面的git仓库中都有详细的实例程序。感兴趣的不妨下载下来跑一跑,看下每个实现的代理工厂类都是如何实现的,非常有助于你真正理解Rpc的调用过程,以及实现自己的Rpc轮子。

以上就是Spring原生Rpc六种的正确打开方式实现示例的详细内容,更多关于Spring原生Rpc打开方式的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot2.0 整合 Dubbo框架实现RPC服务远程调用方法

    一.Dubbo框架简介 1.框架依赖 图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层或模块,蓝色的表示与业务有交互,绿色的表示只对 Dubbo 内部交互. 2)图中背景方块 Consumer, Provider, Registry, Monitor 代表部署逻辑拓扑节点. 3)图中蓝色虚线为初始化时调用,红色虚线为运行时异步调用,红色实线为运行时同步调用. 4)图中只包含 RPC

  • 基于Spring的RPC通讯模型的使用与比较

    一.概念和原理 RPC(remote procedure call),远程过程调用,是客户端应用和服务端之间的会话.在客户端,它所需要的一些功能并不在该应用的实现范围之内,所以应用要向提供这些功能的其他系统寻求帮助.而远程应用通过远程服务暴露这些功能.RPC 是同步操作,会阻塞调用代码的执行,直到被调用的过程执行完毕. Spring支持多种不同的RPC模型,包括RMI.Caucho的Hessian和Burlap以及Spring自带的HTTP invoker: 客户端: 在所有的模型中,服务都是作

  • Java如何实现简单的RPC框架

    一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).Hessian.Http invoker等.另外,RPC是与语言无关的. RPC示意图 如上图所示,假设Computer1在调用sayHi()方法,对于Computer1而言调用sayHi()方法就像调用本地方法一样,调用 –>返回.但从后续调用可以看出Computer1调用的是Computer2

  • Java利用Sping框架编写RPC远程过程调用服务的教程

    RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. RPC 可基于 HTTP 或 TCP 协议,Web Service 就是基于 HTTP 协议的 RPC,它具有良好的跨平台性,但其性能却不如基于 TCP 协议的 RPC.会两方面会直接影响 RPC 的性能,一是传输方式,二是序列化. 众所周知,TCP 是传输层协议,HTTP 是应用层协议,而传输层较应用层更加底层,在数据传输方面,越底层越快,因此,在一般情况下

  • springcloud如何使用dubbo开发rpc服务及调用

    这篇文章主要介绍了springcloud如何使用dubbo开发rpc服务及调用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 spring cloud中基于springboot开发的微服务,是基于http的rest接口,也可以开发基于dubbo的rpc接口. 一,创建goodsService模块 1, 在创建的goodsService模块中再创建goodsServiceApi和goodsServiceServer模块 2,在oodsServic

  • Spring原生Rpc六种的正确打开方式实现示例

    目录 前言 什么是Rpc? Spring中的Rpc 定义服务接口 调用服务代码 WEBSERVICE的RPC实现 服务提供者 服务实现 服务暴露 服务消费者 HTTP的RPC实现 服务提供者 服务实现 服务暴露 服务消费者 文末结语 前言 在java生态圈谈到Rpc,很多人可能就会想到Dubbo.Motan.Grpc等框架.但是你知道吗?作为Java编程全家桶的Spring已经内置了多种RPC的实现方式,可以直接使用.存在即合理,有些场景下其实并不需要Dubbo,Grpc等重量级的RPC组件,那

  • vue-cli + sass 的正确打开方式图文详解

    关于在vue-cli搭建的项目中怎么配置sass,网上搜到的基本是这种答案: 但是我认为,直接将样式写在每个单文件的<style>里,是十分不明智的做法.且不说node-sass安装过程的各种坑,内嵌的<style>也让组件显得十分混乱.想象一下你在修改某个methods时必须拖动滚轮穿越几十上百行的css代码,又或者为了修改一组样式,却找不到对应的css文件,因为它们散布在vue文件里... 在我看来,正确的做法应该是单独管理sass文件,然后在main.js中直接引入编译好的c

  • 基于python的多进程共享变量正确打开方式

    多进程共享变量和获得结果 由于工程需求,要使用多线程来跑一个程序.但是因为听说python的多线程是假的,于是使用多进程,反正任务需要共享的参数少. 查阅资料,发现实现多进程主要使用Multiprocessing,有两种方式,一种是Process,另一种是Pool. p = Process(target=fun,args=(args)) 再通过p.start()来启动一个子进程,通过p.join()方法来使得子进程运行结束后再执行父进程. 但是这样很烦,还要写个for 循环来开n个线程和join

  • 基于Python log 的正确打开方式

    保存代码到文件:logger.py import os import logbook from logbook.more import ColorizedStderrHandler import smtplib LOG_DIR = os.path.join('log') if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR) def get_logger(name='test', file_log=False): logbook.set_date

  • 云开发 VSCode 插件 Cloudbase Toolkit 的正确打开方式及应用场景分析

    什么是 Cloudbase Toolkit Tencent CloudBase Toolkit 是云开发的 VS Code(Visual Studio Code)插件.该插件可以让您更好地在本地进行云开发项目开发和代码调试,并且轻松将项目部署到云端. Cloudbase Toolkit 将项目创建.函数上传.函数更新.函数本地调试等功能集成在 VSCode 的本地调试环境中,开发者可以通过简单的点击,完成云函数的更新.上传.同步等功能. 和 Cloudbase Cli 相比,Cloudbase

  • python中四舍五入的正确打开方式

    round()函数 (注意:下面的我也不清楚是否正确,我只是发表一下我的观点) 对于简单的舍入运算,使用内置的 round(value, ndigits) 函数即可 强烈建议不要去深究,就直接得结果就好 ndigiths可以为正数,也可以为负数,还可以为0,可以为空 n:就是精确到第n位小数,对整数没有影响,1为精确到十分位(注意:小数就是从十分位往后推的) -n:就是精确到整数位,-1为精确到十位,然后就是百位千位-有小数位就全舍掉,不管多大,但会保留一个为0的小数位 0:精确到个位,但会保留

  • TypeScript中extends的正确打开方式详解

    目录 前言 extends第一式:继承 类继承类 接口继承接口 接口继承类 extends第二式:三元表达式条件判断 普通的三元表达式条件判断 情况一:Type1和Type2为同一种类型. 情况二:Type1是Type2的子类型. 情况三: Type2类型兼容类型Type1. 带有泛型的三元表达式条件判断 extends第三式:泛型约束 前言 最近完整地看了一遍TypeScript的官方文档,发现文档中有一些知识点没有专门讲解到,或者是讲解了但却十分难以理解,因此就有了这一系列的文章,我将对没有

  • .NET Core中HttpClient的正确打开方式

    前言 在 Asp.Net Core 1.0 时代,由于设计上的问题, HttpClient 给开发者带来了无尽的困扰,用 Asp.Net Core 开发团队的话来说就是:我们注意到,HttpClient 被很多开发人员不正确的使用.得益于 .Net Core 不断的版本快速升级: 问题来源 长期以来,.NET开发者都通过下面的方式发送http请求: using (var httpClient = new HttpClient()) { var response = await httpClien

  • vue制作加载更多功能的正确打开方式

    使用vue制作加载更多功能,通过ajax获取的数据往data里面push经常不成功,原因是push是往数组中追加数据内容的,而不能用作数组之间的拼接,ajax获取的数据就是数组形式的,因此不成功,应该使用concat()拼接两个数组. //这是错误的写法 $.ajax({ type:'get', async:false, url:path+'no/noticeMobile/getSendNoticeList?imToken='+ getToken +'&pageFlag=2', dataType

  • Vue配置环境变量的正确打开方式

    目录 第一 配置package.json 第二 配置介绍 简单说明 看详情点击上面tps 第三 在根目录新建文件 第四 第五 总结: 第一 配置package.json package.json 里的 scripts 配置 serve test build,通过 --mode xxx 来执行不同环境 通过 npm run serve 启动本地 , 执行 development 通过 npm run test 打包测试 , 执行 testing 通过 npm run build 打包正式 , 执行

随机推荐