Spring原生Rpc六種的正確打開方式實(shí)現(xiàn)示例
前言
在java生態(tài)圈談到Rpc,很多人可能就會(huì)想到Dubbo、Motan、Grpc等框架。但是你知道嗎?作為Java編程全家桶的Spring已經(jīng)內(nèi)置了多種RPC的實(shí)現(xiàn)方式,可以直接使用。存在即合理,有些場(chǎng)景下其實(shí)并不需要Dubbo,Grpc等重量級(jí)的RPC組件,那么Spring的輕量封裝就可以派上用場(chǎng)了。下面就來探索下Spring中的RPC的實(shí)現(xiàn)方式以及如何使用的。
文中代碼地址:https://gitee.com/kailing/spring-rpc
什么是Rpc?
Rpc(Remote Procedure Call): 封裝了內(nèi)部實(shí)現(xiàn)的遠(yuǎn)程調(diào)用過程就是rpc,rpc主要為了簡(jiǎn)化遠(yuǎn)程服務(wù)調(diào)用,通俗的講就是調(diào)用遠(yuǎn)程服務(wù)(跨主機(jī),跨進(jìn)程)就像調(diào)用本地方法一樣。Spring Cloud體系中的Fegin 技術(shù)也可以認(rèn)為是采用http協(xié)議傳輸數(shù)據(jù)的一種Rpc技術(shù)。
Spring中的Rpc
Spring中內(nèi)置了六種不同數(shù)據(jù)傳輸方式的原生的Rpc實(shí)現(xiàn),分別是WebService、Jms、Rmi、Http、Hessian(http)、Amqp。熟悉Rpc的知道,在Java中,主要是通過生成服務(wù)接口的代理來實(shí)現(xiàn)Rpc服務(wù)的調(diào)用,Dubbo、Motan這樣,Spring的實(shí)現(xiàn)也是這樣。在Rpc服務(wù)調(diào)用中,有兩個(gè)角色,分別是服務(wù)的提供者和調(diào)用者(消費(fèi)者)。一方面服務(wù)調(diào)用者通過代理,在服務(wù)調(diào)用時(shí)會(huì)傳輸服務(wù)定義的接口名+方法參數(shù)給到提供者。另一方面服務(wù)提供者拿到接口信息找到本地服務(wù)生成調(diào)用結(jié)果返回給調(diào)用者。所以下面所述六種Rpc實(shí)現(xiàn)都會(huì)有一個(gè)公共的服務(wù)接口定義,以及各自的代理實(shí)現(xiàn)配置。
定義服務(wù)接口
/** * @WebService 注解只用于ws 提供的RPC服務(wù) */ @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的提供者和消費(fèi)者中都會(huì)使用到,提供者中會(huì)實(shí)現(xiàn)這個(gè)接口提供服務(wù),消費(fèi)者會(huì)通過代理,生成這個(gè)接口的代理實(shí)現(xiàn) ,然后通過底層封裝發(fā)送具體的消息。和使用dubbo和motan類似
調(diào)用服務(wù)代碼
@SpringBootApplication public class WsConsumerApplication { @Autowired private AccountService accountService; @PostConstruct public void callRpcService(){ System.out.println("RPC遠(yuǎn)程訪問開始!"); System.err.println(accountService.getAccount("kl").getName()); System.out.println("RPC遠(yuǎn)程訪問結(jié)束!"); } public static void main(String[] args) { SpringApplication.run(WsConsumerApplication.class, args); } }
每個(gè)Rpc實(shí)現(xiàn)都一樣,都是通過注入AccountService 接口的代理實(shí)現(xiàn)來調(diào)用服務(wù)。不過每個(gè)Rpc的代理的配置方式會(huì)略有不同,主要體現(xiàn)在不同的傳輸技術(shù)會(huì)用到不同的配置??偟膩碚f,連接url(http://127.0.0.1、tcp://172.0.0.1、rmi://127.0.0.1),端口、代理接口信息等都是共同需要的。
WEBSERVICE的RPC實(shí)現(xiàn)
服務(wù)提供者
服務(wù)實(shí)現(xiàn)
@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("{} 請(qǐng)求獲取賬號(hào)!", name); Account account = new Account(); account.setName(name + "的賬號(hào)"); return account; } }
和其他服務(wù)實(shí)現(xiàn)不一樣,WebService定義服務(wù)時(shí),需要使用@WebService和@WebMethod注解標(biāo)記
服務(wù)暴露
@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; } }
完成如上代碼,其實(shí)我們已經(jīng)構(gòu)建了一個(gè)完整的WebService服務(wù),而且還加上了用戶、密碼和ip白名單等接口權(quán)限認(rèn)證,訪問:http://127.0.0.1:8083/AccountServiceImpl?WSDL 就可以看到服務(wù)的定義,如下:
服務(wù)消費(fèi)者
@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的代理實(shí)例。當(dāng)注入服務(wù)調(diào)用方法時(shí),實(shí)際上是觸發(fā)了一次WebService的遠(yuǎn)程調(diào)用
HTTP的RPC實(shí)現(xiàn)
服務(wù)提供者
服務(wù)實(shí)現(xiàn)
@Service public class AccountServiceImpl implements AccountService { Logger logger = LoggerFactory.getLogger(getClass()); @Override public Account getAccount(String name) { logger.info("{} 請(qǐng)求獲取賬號(hào)!", name); Account account = new Account(); account.setName(name + "的賬號(hào)"); return account; } }
服務(wù)暴露
@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; } }
服務(wù)消費(fèi)者
@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實(shí)現(xiàn)的Rpc服務(wù)消費(fèi)者時(shí),和WebService是類似的,定義一個(gè)FactoryBean就ok了。其實(shí)其他的四種Rpc實(shí)現(xiàn)也都大同小異。后面就不一一列舉了
文末結(jié)語
博文起草構(gòu)思的時(shí)候本來打算將Spring中內(nèi)置六種Rpc實(shí)現(xiàn)都詳細(xì)描述下,后面看著看著就覺得使用起來真的很類似。只不過像Amqp和Jms以及WebService等實(shí)現(xiàn)需要有這方面技術(shù)經(jīng)驗(yàn)的人才能看的明白。但單就Rpc使用和實(shí)現(xiàn)來說基本差不多,所以后面就沒有一一列出占用篇幅。但是上面提到的WebService、Jms、Rmi、Http、Hessian、Amqp這六種實(shí)現(xiàn)在上面的git倉(cāng)庫(kù)中都有詳細(xì)的實(shí)例程序。感興趣的不妨下載下來跑一跑,看下每個(gè)實(shí)現(xiàn)的代理工廠類都是如何實(shí)現(xiàn)的,非常有助于你真正理解Rpc的調(diào)用過程,以及實(shí)現(xiàn)自己的Rpc輪子。
以上就是Spring原生Rpc六種的正確打開方式實(shí)現(xiàn)示例的詳細(xì)內(nèi)容,更多關(guān)于Spring原生Rpc打開方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于idea一直卡在build不動(dòng)的解決方案
這篇文章主要介紹了idea一直卡在build不動(dòng)的解決方案,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10java動(dòng)態(tài)構(gòu)建數(shù)據(jù)庫(kù)復(fù)雜查詢教程
這篇文章主要介紹了java動(dòng)態(tài)構(gòu)建數(shù)據(jù)庫(kù)復(fù)雜查詢的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-11-11JDK8 new ReentrantLock((true)加鎖流程
這篇文章主要介紹了java面試中常遇到的問題JDK8 new ReentrantLock((true)加鎖流程示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07淺談java object對(duì)象在heap中的結(jié)構(gòu)
本文主要介紹了淺談java object對(duì)象在heap中的結(jié)構(gòu),感興趣的同學(xué),可以參考下。2021-06-06Java中的synchronized和ReentrantLock的區(qū)別詳細(xì)解讀
這篇文章主要介紹了Java中的synchronized和ReentrantLock的區(qū)別詳細(xì)解讀,synchronized是Java內(nèi)建的同步機(jī)制,所以也有人稱其為 IntrinsicLocking,它提供了互斥的語義和可見性,當(dāng)一個(gè)線程已經(jīng)獲取當(dāng)前鎖時(shí),其他試圖獲取的線程只能等待或者阻塞在那里,需要的朋友可以參考下2024-01-01