本文將經過具體的遠程服務發佈與消費案例展現4種RPC遠程調用方法.html
java.rmi
包, 方便開發者進行遠程服務的部署與消費, 下面將經過具體案例進行講解.UserService
接口.//將要發佈的服務的接口
public interface UserService extends Remote {
public String helloRmi(String name) throws RemoteException;
}
複製代碼
UserServiceImpl
實現類UserServiceImpl
除了實現UserService
接口外, 還要繼承UnicastRemoteObject
類, 你能夠理解爲它是一個發佈出去供他人調用的類, 當UserServiceImpl
實現了這個類後, UserServiceImpl
就能被髮布出去供別人調用.//將要發佈的服務的實現類
public class UserServiceImpl extends UnicastRemoteObject implements UserService {
public UserServiceImpl() throws RemoteException {
super();
}
public String helloRmi(String name) throws RemoteException {
return "hello " + name;
}
}
複製代碼
public static void main(String[] args) {
try {
//完成遠程服務的發佈
LocateRegistry.createRegistry(8888);//將遠程服務發佈在本地的8888端口
String name = "rmi://localhost:8888/rmi";//發佈的遠程服務被訪問的url
UserService userService = new UserServiceImpl();//建立一個提供具體服務的遠程對象
Naming.bind(name, userService);//給遠程服務綁定一個url
System.out.println("--- 已發佈rmi遠程服務 ---");
} catch (Exception e) {
e.printStackTrace();
}
}
複製代碼
rmi-provider
項目種的UserService
接口與UserServiceImpl
實現類複製到本rmi-consumer
項目中.(這一步能夠進行優化解耦, 咱們能夠多建立一個rmi-resource
項目, 讓rmi-provider
和rmi-consumer
共同依賴rmi-resource
項目, 而後把資源文件好比遠程服務所用到的UserService
等放入rmi-resource
項目中)public static void main(String[] args) {
try {
//發佈遠程服務的訪問url
String name = "rmi://localhost:8888/rmi";
//經過發佈遠程服務的url, 獲取遠程服務的代理對象
UserService userService = (UserService) Naming.lookup(name);
System.out.println("得到的遠程服務的代理對象:" + userService.getClass().getName());
String result = userService.helloRmi("rmi");//拿到遠程方法調用的結果
System.out.println("result: " + result);
}catch (Exception e) {
e.printStackTrace();
}
}
//最後輸出
得到的遠程服務的代理對象:com.sun.proxy.$Proxy0
result: hello rmi
複製代碼
http + xml
進行通訊.UserService
及其實現類UserServiceImpl
.WebService
時須要對遠程服務加上註解@WebService
@WebService
public interface UserService {
public String sayHello(String name);
}
@WebService
public class UserServiceImpl implements UserService {
@Override
public String sayHello(String name) {
return "hello " + name + "~";
}
}
複製代碼
rmi
差很少, 須要提供遠程服務的訪問地址和具體的遠程服務實現類, 使用Endpoint
類的publish()
方法進行發佈, 這都是JDK封裝好的.public class WsProviderApp {
public static void main(String[] args) {
//發佈的WebService的被訪問地址
String address = "http://localhost:9999/ws";
//建立遠程服務對象
UserService userService = new UserServiceImpl();
//發佈服務
Endpoint.publish(address, userService);
System.out.println("遠程服務已經發布...");
}
}
複製代碼
rmi
不一樣的是, WebService發佈後, 調用者能夠經過查看它的文檔對遠程服務發起調用.?wdsl
, 好比本案例中是http://localhost:9999/ws?wsdl
bin
目錄下, 名字是wsimport
wsimport -keep -d C:\githubRepositories\shopping\ws-consumer\src\main\java -p com.shenghao.client http://localhost:9999/ws?wsdl
解釋:
1. wsimport 是命令的名字
2. -keep 用於保留生成的類, 若是沒有該指令會只生成class文件 3. -d 後面接項目中存放這些工具類的包, 填絕對路徑 4. -p 填wdsl文檔的地址 複製代碼
5. 能夠看到命令執行完後, 指定的包中出現一堆相關的類, 最直接調用到的類是UserServiceImplService
. 下面演示對遠程方法進行調用.java
public static void main(String[] args) {
//建立服務類對象
UserServiceImplService service = new UserServiceImplService();
//得到遠程服務的代理對象
UserServiceImpl userService = service.getUserServiceImplPort();
System.out.println(userService.getClass().getName());
//對遠程服務對象的方法進行調用
String result = userService.sayHello("炭燒生蠔");
System.out.println(result);
}
//結果輸出
com.sun.proxy.$Proxy32
hello 炭燒生蠔~
複製代碼
<html>
標籤, 而是json
字符串. 微信小程序先後端通訊也是這個原理.order-sys
的Maven項目, 指定打包爲war
包.
<properties> <!-- spring 依賴 --> <spring.version>4.3.18.RELEASE</spring.version> <jstl.version>1.2</jstl.version> <servlet-api.version>2.5</servlet-api.version> <jsp-api.version>2.0</jsp-api.version> <jackson.version>2.9.0</jackson.version> </properties> <dependencies> <!-- jsp相關依賴 --> <!-- servlet依賴 --> <!-- jstl依賴 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> </dependency> <!-- springmvc依賴--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> </dependencies> <build> <finalName>order</finalName> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/order</path> <port>7070</port> </configuration> </plugin> </plugins> </build></code></p> 複製代碼
複製代碼<properties> <!-- spring 依賴 --> <spring.version>4.3.18.RELEASE</spring.version> <jstl.version>1.2</jstl.version> <servlet-api.version>2.5</servlet-api.version> <jsp-api.version>2.0</jsp-api.version> <jackson.version>2.9.0</jackson.version> </properties> <dependencies> <!-- jsp相關依賴 --> <!-- servlet依賴 --> <!-- jstl依賴 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> </dependency> <!-- springmvc依賴--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> </dependencies> <build> <finalName>order</finalName> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/order</path> <port>7070</port> </configuration> </plugin> </plugins> </build></code></p> 複製代碼
2. 建立訂單類git
public class Order {
private String id;
private Double total;
private String date;
//get / set ...
}
複製代碼
- 對外提供服務, 發佈時打包發佈到
Tomcat
上
@Controller
public class OrderController {
/** * 接收http請求, 響應訂單集合, 異步響應 * 將list集合序列化爲json串響應 * @param uid * @return */
@RequestMapping("/loadOrderList2")
@ResponseBody
public List<Order> loadOrderList2(String uid){
System.out.println("uid: " + uid);
//模擬訂單數據
Order o1 = new Order();
o1.setId("111");
o1.setTotal(333.33);
o1.setDate("2019-4-29");
Order o2 = new Order();
o2.setId("222");
o2.setTotal(444.44);
o2.setDate("2019-5-29");
Order o3 = new Order();
o3.setId("333");
o3.setTotal(555.55);
o3.setDate("2019-6-29");
List<Order> list = new ArrayList<>();
list.add(o1);
list.add(o2);
list.add(o3);
return list;
}
}
複製代碼
遠程服務消費者實現
- 在服務消費端使用
HttpClient
發送請求, 能夠理解爲模擬瀏覽器發送post/get請求. HttpClient
爲咱們封裝了拼接一個請求的細節, 使得發送一個請求變得容易.
public static void main(String[] args) throws IOException {
//發送遠程的http請求的地址
String url = "http://localhost:7070/order/loadOrderList2";
//建立HttpClient對象
CloseableHttpClient client = HttpClients.createDefault();
//建立HttpPost對象, 發送post請求
HttpPost method = new HttpPost(url);
//封裝發送到服務提供者的參數
NameValuePair id = new BasicNameValuePair("uid", "10001");
List<NameValuePair> params = new ArrayList<>();
params.add(id);
//封裝請求體數據
method.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
//發送具體的http請求
HttpResponse response = client.execute(method);
//得到服務提供者響應的具體數據
HttpEntity entity = response.getEntity();
//得到http的響應體
InputStream is = entity.getContent();
int len = 0;
char[] buf = new char[1024];
//使用字符流讀
InputStreamReader reader = new InputStreamReader(is);
StringBuffer sb = new StringBuffer();
while((len = reader.read(buf)) != -1){
sb.append(String.valueOf(buf, 0, len));
}
System.out.println(sb);
//將響應回來的json字符串解析爲Order集合
List<Order> list = JSON.parseArray(sb.toString(), Order.class);
for(Order o : list){
System.out.println(o.getId() + "\t" + o.getTotal() + "\t" + o.getDate());
}
}
複製代碼
四. 經過spring提供的RestTemplate實現遠程服務的生產與消費
- 經過一個紅包系統和訂單系統進行演示, 紅包系統訪問訂單系統, 得到某個用戶的訂單信息, 派發紅包.
- 訂單系統繼續沿用
HttpClient
中的訂單系統, 經過訪問loadOrderList2
方法能返回一個訂單集合Json字符串.
遠程服務消費者實現.
@Controller
public class RedController {
//注入由spring提供的RestTemplate對象
@Autowired
private RestTemplate restTemplate;
/** * 發送遠程的http請求, 消費http服務 * 得到訂單對象的集合 */
@RequestMapping("/loadOrderList3")
@ResponseBody
public List<ResponseEntity<Order[]>> loadOrderList3(String uid){
//發送遠程http請求的url
String url = "http://localhost:7070/order/loadOrderList2";
//發送到遠程服務的參數
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("uid", uid);
//經過RestTemplate對象發送post請求
ResponseEntity<Order[]> entitys = restTemplate.postForEntity(url, params, Order[].class);
//查看響應的狀態碼
System.out.println(entitys.getStatusCodeValue());
//查看響應頭
HttpHeaders headMap = entitys.getHeaders();
for(Map.Entry<String, List<String>> m : headMap.entrySet()){
System.out.println(m.getKey() + ": " + m.getValue());
}
return Arrays.asList(entitys);
}
}
複製代碼