(三)遠端服務:RMI 服務實現遠端呼叫
RMI 與 Spring
RMI 是 Java 平臺實現遠端呼叫的一種方式,於 JDK1.1 引入 Java 平臺。“Spring 簡化了 RMI 模型,它提供了一個代理工廠 Bean ,能讓我們把 RMI 服務像本地 JavaBean 一樣裝配到我們的 Spring 應用中。”這裡再多說一句, RMI 是 RPC 在 Java 平臺的一種實現方式。
RMI 使用的注意事項
RMI 釋出服務和呼叫服務需要指定埠,這意味著需要穿越防火牆,如果需要訪問外網的話。
RMI 的服務端涉及到兩個埠,即註冊埠和服務埠,註冊埠相當於服務的接線員,服務埠是客戶端真正要找的業務人員。註冊埠預設為1099,服務埠是隨機分配的,所以在有防火牆的情況下需要自己指定。
RMI 是基於 Java 的,那麼服務端和客戶端都必須是 Java 開發的。
如果客戶端配置為快取服務端服務(即客戶端 cacheStub=true),那麼在伺服器端重啟的時候,客戶端呼叫會報錯,解決辦法有兩個:一個是客戶端設定無快取(即客戶端 cacheStub=false),再一個方法是允許快取呼叫失敗後從新發起配置呼叫(refreshStubOnConnectFailure=true)。所以到這裡,可以理解為 RMI 遠端呼叫需要通過註冊埠建立通道,然後通過服務埠訪問業務。
如果需要在遠端呼叫中傳輸物件,必須注意 Java 物件的序列化問題(傳送門)。
RMI-Spring 測試概況
我們使用三個專案來完成整個測試。
- api :定義介面和實體資訊,內含抽象方法。
- server:實現api中的介面,並且對外提供 RMI 遠端服務。啟動方式為 main 函式啟動。
- consumer:一個web專案,通過配置將遠端服務注入到本地介面實現遠端呼叫。
- master:Maven 聚合父專案,便於clean 、install。
api 主要程式碼
- 實體類 Model.java
import java.io.Serializable;
public class Model implements Serializable {
private static final long serialVersionUID = 1L;
private String userName;
private int age;
//get\set 方法略
}
- 介面 ApiService.java
public interface ApiService {
String getName(String name);//輸入什麼,返回什麼
Model getModel();//返回實體類-測試遠端傳遞物件
}
server 主要程式碼
- 介面實現類 ApiServiceImpl.java
public class ApiServiceImpl implements ApiService{
@Override
public String getName(String name) {
System.out.println("服務端被呼叫");
return name;
}
@Override
public Model getModel() {
Model m=new Model();
m.setUserName("jecket");
m.setAge(20);
return m;
}
}
- Spring Bean 註冊與遠端服務配置
可以使用註解配置
- Java 配置類
@Configuration
public class RpcBean {
/**
* 註冊為遠端服務
* @return
*/
@Bean
public RmiServiceExporter rmiExporter(){
RmiServiceExporter rmi=new RmiServiceExporter();
rmi.setService(getApiService());//介面實現 Spring Bean
rmi.setServiceName("ApiService");//遠端服務名字
rmi.setServiceInterface(ApiService.class);//介面
rmi.setRegistryPort(8080);//遠端服務註冊埠
rmi.setServicePort(8082);//遠端服務業務訪問埠
return rmi;
}
/**
* 註冊為Spring Bean
* @return
*/
@Bean
public ApiService getApiService(){
return new ApiServiceImpl();
}
}
- Spring 配置掃描資訊
<context:component-scan base-package="com.bestcxx.stu.rpc.rmi.bean"/><!--RpcBean.java 所在包路勁 -->
也可以使用xml的配置方式
- Spring 配置檔案內容
<bean id="apiService" class="com.bestcxx.stu.rpc.rmi.service.ApiServiceImpl" /> <!--Spring bean-->
<bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter"> <!--RMI 遠端服務配置-->
<property name="service" ref="apiService" />
<property name="serviceName" value="apiService" />
<property name="serviceInterface" value="com.bestcxx.stu.rpc.rmi.api.ApiService" />
<property name="registryPort" value="8080" /><!-- 註冊埠 -->
<property name="servicePort" value="8080"/><!-- 通訊埠,不指定就隨機 -->
</bean>
- 啟動 Server
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath:spring/applicationContext-bean.xml");
System.out.println("服務端啟動...");
}
consumer 主要程式碼
- 為遠端服務設定代理服務,註冊為本地Bean
可以使用註解配置
rmi://127.0.0.1:8080/ApiService 中,127.0.0.1是遠端服務地址,8080是遠端服務註冊埠,ApiService 是遠端服務名稱
@Configuration
public class RpcBean {
@Bean
public RmiProxyFactoryBean apiService(){
RmiProxyFactoryBean rmiProxy=new RmiProxyFactoryBean();
//遠端服務地址,直接指定了具體的host、ip、服務名稱
rmiProxy.setServiceUrl("rmi://192.168.149.1:8080/ApiService");
//rmiProxy.setServiceUrl("rmi://127.0.0.1:8080/ApiService");
//定義遠端服務介面,服務端是該介面對應遠端服務的實現
rmiProxy.setServiceInterface(ApiService.class);
//定義是否在首次配置遠端服務後快取該配置
rmiProxy.setCacheStub(true);
//如果遠端呼叫快取配置報錯,設定為true,允許重新呼叫
rmiProxy.setRefreshStubOnConnectFailure(false);
//是否在客戶端啟動的時候檢測服務端服務可用性-測試發現該屬性沒有發揮作用
rmiProxy.setLookupStubOnStartup(false);
return rmiProxy;
}
}
- Spring 配置掃描資訊
<context:component-scan base-package="com.bestcxx.stu.rpc.rmi.bean"/><!--RpcBean.java 所在包路勁 -->
也可以使用xml配置
<bean id="apiService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://192.168.149.1:8080/ApiService" />
<property name="serviceUrl" value="rmi://localhost:8080/ApiService" />
<property name="refreshStubOnConnectFailure" value="true" />
<property name="lookupStubOnStartup" value="false" />
<property name="serviceInterface" value="com.bestcxx.stu.rpc.rmi.api.ApiService" />
</bean>
- controller 層呼叫
@RestController
public class HomeController {
@Autowired
private ApiService apiService;
/**
* Controller 訪問案例,根據id訪問資料庫
* @return
*/
@RequestMapping("/home")
public Map<String,Object> home(){
Map<String,Object> map=new HashMap<String,Object>();
String name=apiService.getName("jecket");//呼叫 String 型別返參方法
Model m=apiService.getModel();//呼叫物件型別返參方法
map.put("result", "success");
map.put("name", name);
map.put("model", m);
return map;
}
}
結果展示
服務端在本地啟動,客戶端不知道其他網路環境訪問
- 伺服器端:
服務端啟動...
服務端被呼叫
- 瀏覽器訪問客戶端
{"result":"success","name":"jecket","model":{"userName":"jecket","age":20}}
github 地址
相關推薦
(三)遠端服務:RMI 服務實現遠端呼叫
RMI 與 Spring RMI 是 Java 平臺實現遠端呼叫的一種方式,於 JDK1.1 引入 Java 平臺。“Spring 簡化了 RMI 模型,它提供了一個代理工廠 Bean ,能讓我
【遠端呼叫框架】如何實現一個簡單的RPC框架(三)優化一:利用動態代理改變使用者服務呼叫方式
【如何實現一個簡單的RPC框架】系列文章: 這篇部落格,在(一)(二)的基礎上,對第一版本實現的服務框架進行改善,不定期更新,每次更新都會增加一個優化的地方。 1、優化一:利用動態代理改變使用者服務呼叫方式 1.1 目的 改變使用者
(三)整合spring cloud雲服務架構 - particle雲架構代碼結構構建
itl log lan 作用 購物 基本架構 集成 eight control 上一篇介紹了spring cloud雲服務架構的基本架構圖,本篇我們根據架構圖進行代碼的構建,根據微服務化設計思想,結合spring cloud本身的服務發現、治理、配置化管理、分布式等項目優秀
【WCF系列】(三)如何配置和承載服務
支持 一個 地址 BE eof spa 介紹 alt contract 如何配置和承載服務 配置綁定 配置服務:任務 為什麽要配置服務:在設計和實現服務協定後,即可配置服務。 在其中可以定義和自定義如何向客戶端公開服務指定可以找到服務的地址、服務用於發送和接收消息的傳
Linux 筆記 - 第十三章 Linux 系統日常管理之(三)Linux 系統日誌和服務
pac ica link tor 包含 3.1 request closed comm 博客地址:http://www.moonxy.com 一、前言 日誌文件記錄了系統每天發生的各種各樣的事情,比如監測系統狀況、排查問題等。作為系統運維人員可以通過日誌來檢查錯誤發生的原因
Reactive程式設計(三):一個簡單的HTTP服務
書接上文 Reactive程式設計 ,我們已經瞭解了基礎的API,現在我們開始編寫實際的應用。Reactive對併發程式設計進行了很好的抽象,也有很多底層的特性需要我們去關注。當使用這些特性時,我們可以對之前隱藏在容器、平臺、框架中的細節進行控制。 Spr
API 限流器(三) 在Spring Cloud 微服務體系中整合RedisRateLimiter
這篇是API限流器這個系列的終章,就是講述如何在Spring Cloud 微服務開發中應用我發明的先進限流器。開篇明義,基本思路如下:1. 定義一個annotation - RedisLimiter2. 在RestController 中有URL Mapping 的方法上
工作流總結(三)JBPM 六個流程服務介面
在說明六個核心服務之前,需要提到的是ProcessEngine物件。類似一個工廠提供流程過程中所需的服務,抽象工廠設計模式的體現。而ProcessEngine物件是由Configruation物件來建立的,ProcessEngine是一個執行緒安全的物件,保證我
[日更-2019.5.20] Android 系統內的守護程序(三)--core類中的服務 : lmkd
宣告 其實很好奇Android系統中的一些關鍵守護程序服務的作用; 暫且大概分析下它們的作用,這樣有助於理解整個系統的工作過程;
學習之路(三)淺談:輸出重定向,grep及正則表達式,egrep
grep 地址總線:內存尋址 數據總線:傳輸數據 控制總線:控制指令 > :輸出重定向(會覆蓋原有內容) >>: 追加重定向(不會覆蓋,追加輸出) 2>: 重定向錯誤輸出 2
熟練使用Lua(三)模組支援:require的載入module的基本原理(1)
Lua標準庫- 模組(Modules) 轉: https://www.cnblogs.com/jadeboy/p/4150048.html Lua包庫為lua提供簡易的載入及建立模組的方法,由require、module方法及package表組成 1、module (nam
《好好學習》讀書筆記(三)第二章:掌握臨界知識的方法
目錄 心態準備 1.新舊知識建立聯絡 2.發掘新知識的通用性 3.花慢功夫死磕關鍵知識,打通知識網的要塞,融匯貫通 具體方法 1.反思 2.以教為學 3.
目標檢測入門之(三)RCNN系列:RCNN->SppNET->Fast-RCNN->Faster-RCNN
object detection,就是在給定的圖片中精確找到物體所在位置,並標註出物體的類別。object detection要解決的問題就是物體在哪裡,是什麼這整個流程的問題。然而,這個問題可不是那麼容易解決的,物體的尺寸變化範圍很大,擺放物體的角度,姿態不定,而且可以
《好好學習》閱讀筆記(三)第二章:掌握臨界知識的方法
目錄 心態準備 具體方法 1.反思 心態準備 1.新舊知識建立聯絡 連線成網,從不同角度和領域對同一個知識進行分析,加深理解 [----知識結構 章魚狀 -》蜂窩狀] [----思維導圖試記憶-》殿堂式記憶(like sherlock)]
自定義註解(三)支付渠道:消除if-策略模式+工廠模式+單例模式
自定義支付註解=消除if:策略模式+工廠模式+單例模式 程式碼取景,知識來源於視訊《雲析學院【路飛老師】-一次學習終身受用-如何正確使用設計模式寫出優雅的程式碼》 1、定義註解標籤 PayChannel @Target(ElementType.TYPE) @Re
樹莓派入門(三)- 基本設定:時區、密碼、apt-get源、上傳下載
樹莓派基本設定 更改時區 修改root、pi密碼 更換apt為阿里雲源 使用lrzsz,上傳下載檔案 更改時區 輸入命令 sudo dpkg-reconfigure tzdata 上下箭頭移動游標,
Android Studio專案打包(三)打包說明:release和debug版本的區別、v1和v2的簽名使用等等
android中匯出簽名的,apk的release和debug版本的區別 (1)debug簽名的應用程式不能在Android Market上架銷售,它會強制你使用自己的簽名;Debug模式下簽名用的證書(預設是Eclipse/ADT和Ant編譯)自從它建立之日起,1年後就會失效。 (2)
Oracle:PL/SQL--流程控制(三)——迴圈結構:loop、while-loop、for-loop
—–流程控制(三) —–迴圈結構 —–1、loop迴圈 語法: loop statements; end loop; —–實現計數器功能,當計數器為10或者大於10時退出 declare v_count integer :=
Android網路程式設計TCP、UDP(三)——UDP例項:搜尋區域網所有的裝置
接上面的UDP,本篇主要討論如何在區域網中搜索所有的裝置,這個需求在物聯網應用的比較多,也比較綜合,特把名字加在標題中了。最後一塊是網路程式設計的常見問題。 3.6 例項:在區域網內搜尋裝置 假設你家裡安裝了智慧家居,所有的裝置都是通過Wifi連線自己家
java中文亂碼解決之道(三)-----編碼詳情:偉大的創想---Unicode編碼
隨著計算機的發展、普及,世界各國為了適應本國的語言和字元都會自己設計一套自己的編碼風格,正是由於這種亂,導致存在很多種編碼方式,以至於同一個二進位制數字可能會被解釋成不同的符號。為了解決這種不相容的問題