Spring原生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轮子。
作者简介:
陈凯玲,2016年5月加入凯京科技。现任凯京科技研发中心架构&运维部架构组经理。独立博客KL博客(http://www.kailing.pub)博主。
欢迎加入凯京开源技术QQ群:613025121,和我们一起交流互联网应用的技术架构落地实践
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
【Python 学习进阶月刊】 第二期: Python 资料汇总
欢迎订阅Python学习进阶月刊 精彩直播: Python 系列直播——深入Python与日志服务,玩转大规模数据分析处理实战 IPython/Jupyter Notebook非常流行,但随着数据量越来越大(例如几百亿条电商平台访问日志),如何继续保持灵活的交互式分析,是一个挑战。阿里云日志服务作为阿里商业操作系统的智能运维平台,无需开发就能快捷完成海量日志数据的采集、消费、投递以及查询分析等功能。这里介绍如何借助日志服务对IPython/Jupyter扩展的功能,用Python对海量数据进行深度加工(ETL)、交互式分析(通过SQL、DataFrame)、机器学习与可视化等。点击查看 Python 第九讲——灵活运用docker,实现深度学习的环境搭建Python 系列直播——深入Python与日志服务,玩转大规模数据分析处理实战第五讲 技术干货 pyppeteer持久化修改网站检测浏览器的特征值Python爬虫入门教程 10-100 图虫网多线程爬取pyppeteer最为核心类Page的接口方法pyppeteer的Browser类及其BrowserContext类Python爬虫入...
- 下一篇
Python3破冰人工智能,你需要掌握一些数学方法
为什么要把数学建模与当今火热的人工智能放在一起? 首先,数学建模在字面上可以分解成数学+建模,即运用统计学、线性代数和积分学等数学知识,构建算法模型,通过模型来解决问题。数学建模往往是没有对与错,只有“更好”(better),就好像让你评价两个苹果哪个更好吃,只有好吃、不好吃或者更好吃,没有对与错。 人工智能(ArtificialIntelligence,AI),你可以将其理解为是一种“黑科技”,人类通过它,让计算机能够“更好”地像人一样思考。可以说“算法模型”是人工智能的“灵魂”,没有算法模型,一切都是“水中月”“镜中花”! 因此,《Python 3破冰人工智能》将从数学建模入手,由浅入深地为读者揭开AI的神秘面纱。 数学建模 数学建模与人工智能 1.数学建模简介 数学建模是利用数学方法解决实际问题的一种实践。即通过抽象、简化、假设、引进变量等处理过程,将实际问题用数学方式表达,建立起数学模型,然后运用先进的数学方法及计算机技术进行求解。数学建模可以通俗地理解为数学+建模,即运用统计学、线性代数,积分学等数学知识,构建数学模型,通过模型解决问题。 按照传统定义,数学模型是对于一个现实...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS8安装Docker,最新的服务器搭配容器使用
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS关闭SELinux安全模块
- Linux系统CentOS6、CentOS7手动修改IP地址
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2整合Thymeleaf,官方推荐html解决方案