目錄
三 項目git https://github.com/HandsomeMars/springboot-ice-demo
一 前言
1、基於上篇ice簡單使用,本篇文章講講如何實現客戶端與服務端之間雙向調用
2、本文列舉兩種實現:
- java main方法調用
- 結合spring IOC容器管理
二 實現
1、目錄結構
├─main
│ ├─java
│ │ │ .depend
│ │ │
│ │ ├─com
│ │ │ └─zyj
│ │ │ │ SpringbootIceCallClientApplication.java #springweb啓動類
│ │ │ │
│ │ │ ├─ice
│ │ │ │ ├─java
│ │ │ │ │ ├─client
│ │ │ │ │ │ IceClient.java #java客戶端
│ │ │ │ │ │
│ │ │ │ │ └─server
│ │ │ │ │ IceService.java #java服務端
│ │ │ │ │
│ │ │ │ ├─servant
│ │ │ │ │ ClientServant.java #客戶端實現
│ │ │ │ │ ServerServant.java #服務端實現
│ │ │ │ │
│ │ │ │ └─spring
│ │ │ │ ├─client
│ │ │ │ │ IceClient.java #srping客戶端
│ │ │ │ │
│ │ │ │ └─server
│ │ │ │ IceService.java #srping服務端
│ │ │ │
│ │ │ └─util
│ │ │ SpringContextUtil.java
│ │ │
│ │ └─slice2java
│ │ Callback_IServerCallBack_response.java
│ │ Callback_IServer_request.java
│ │ Callback_IServer_setCallBack.java
│ │ IServer.java
│ │ IServerCallBack.java
│ │ IServerCallBackHolder.java
│ │ IServerCallBackPrx.java
│ │ IServerCallBackPrxHelper.java
│ │ IServerCallBackPrxHolder.java
│ │ IServerHolder.java
│ │ IServerPrx.java
│ │ IServerPrxHelper.java
│ │ IServerPrxHolder.java
│ │ _IServerCallBackDisp.java
│ │ _IServerCallBackOperations.java
│ │ _IServerCallBackOperationsNC.java
│ │ _IServerDisp.java
│ │ _IServerOperations.java
│ │ _IServerOperationsNC.java
│ │
│ └─resources
│ │ application.properties #springweb項目
│ ├─lib
│ │
│ │ Identity.ice #ice公共文件 拷貝至此解除軟件環境依賴
│ └─slice
│ call.ice #ice協議文件
│
└─test
└─java
└─com
└─zyj
SpringbootIceCallClientApplicationTests.java
2、公共代碼
call.ice
#include <E:\SpringWorkSpace\springboot-ice-demo\springboot-ice-call\src\main\resources\lib\Identity.ice>
module slice2java{
/****************
ice客戶端
*****************/
interface IServerCallBack {
/****************
客戶端處理服務端返回
*****************/
bool response(string msg);
};
/***************
ice服務端
****************/
interface IServer {
/***************
服務端設置客戶端回調對象
****************/
bool setCallBack(Ice::Identity id);
/***************
服務端處理客戶端請求
****************/
bool request(string msg);
};
};
ice文件解釋
#include 標識當前ice文件包含其他文件
E:\SpringWorkSpace\springboot-ice-demo\springboot-ice-call\src\main\resources\lib\Identity.ice 爲ice公共文件
/****************
註釋內容
*****************/
ClientServant.java
package com.zyj.ice.servant;
import Ice.Current;
import slice2java._IServerCallBackDisp;
/**
* @author by zyj
* @version V1.0
* @Description:
* @Date 2019/8/6 21:13
*/
@Service
//spring模式bean託管
public class ClientServant extends _IServerCallBackDisp {
/**
* 客戶端處理服務端返回
*
* @param msg
* @param __current The Current object for the invocation.
**/
@Override
public boolean response(String msg, Current __current) {
System.out.println("serverCallBack:" + msg);
return false;
}
}
ServerServant.java
package com.zyj.ice.servant;
import Ice.*;
import org.springframework.stereotype.Service;
import slice2java.IServerCallBackPrx;
import slice2java.IServerCallBackPrxHelper;
import slice2java._IServerDisp;
/**
* @author by zyj
* @version V1.0
* @Description:
* @Date 2019/8/6 21:13
*/
@Service
//spring模式使用bean託管
public class ServerServant extends _IServerDisp {
/**
* 服務端設置客戶端回調對象
*
* @param id
* @param __current The Current object for the invocation.
**/
@Override
public boolean setCallBack(Identity id, Current __current) {
IServerCallBackPrx iServerCallBackPrx = IServerCallBackPrxHelper.uncheckedCast(__current.con.createProxy(id));
iServerCallBackPrx.ice_getConnection().setCallback(new ConnectionCallback() {
@Override
public void heartbeat(Connection c) {
System.out.println("sn:" + " client heartbeat....");
}
@Override
public void closed(Connection c) {
System.out.println("sn:" + " " + "closed....");
}
});
// 每30/2 s向對方做心跳
// 客戶端向服務端做心跳 服務端打印服務端的con.setCallback(new Ice.ConnectionCallback()
iServerCallBackPrx.ice_getConnection().setACM(new IntOptional(10), new Optional<ACMClose>(ACMClose.CloseOff),
new Optional<ACMHeartbeat>(ACMHeartbeat.HeartbeatAlways));
return true;
}
/**
* 服務端處理客戶端請求
*
* @param msg
* @param __current The Current object for the invocation.
**/
@Override
public boolean request(String msg, Current __current) {
System.out.println("client:" + msg);
return false;
}
}
3、java實現
step1: ServerServant 實現服務端 如上
setp2:配置server
package com.zyj.ice.java.server;
import com.zyj.ice.servant.ServerServant;
/**
* @author by zyj
* @version V1.0
* @Description:
* @Date 2019/8/6 21:13
*/
public class IceService {
/**
* 服務名
*/
private static final String SERVER_NAME = "Hello";
/**
* 服務端點
*/
private static final String SERVER_ENDPOINT = "tcp -p 10006";
public static void main(String[] args) {
//獲取實現類 SpringContextUtil.getBean(helloServant)
ServerServant serverServant = new ServerServant();
//ice通信器
Ice.Communicator communicator = null;
try {
//初始化ice通信器communicator,可以使用args傳入一下ice初始化的參數如超時時間,線程池大小等
communicator = Ice.Util.initialize(args);
//創建一個名爲queryEmployeeAdapter的適配器並且默認使用tcp協議 服務部署在10.4.30.81機器上 服務開啓10006監聽端口
Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints(SERVER_NAME, SERVER_ENDPOINT);
// 將servant與ice對象標識符建立映射關係,並添加到ice對象適配器中
adapter.add(serverServant, Ice.Util.stringToIdentity(SERVER_NAME));
// 激活對象適配器
adapter.activate();
System.out.println("服務啓動");
// 服務在退出之前一直保持監聽狀態
communicator.waitForShutdown();
} catch (Exception e) {
e.printStackTrace();
} finally {
//異常銷燬通信器
if (communicator != null) {
communicator.destroy();
}
}
}
}
step3:IceClient 實現ClientServant
step4:IceClient 連接server並設置回調
package com.zyj.ice.java.client;
import Ice.Identity;
import Ice.StringHolder;
import com.zyj.ice.servant.ClientServant;
import slice2java.IServerPrx;
import slice2java.IServerPrxHelper;
/**
* @author by zyj
* @version V1.0
* @Description:
* @Date 2019/8/6 21:13
*/
public class IceClient {
/**
* 服務名
*/
private static final String SERVER_NAME = "Hello";
/**
* 服務端點
*/
private static final String SERVER_ENDPOINT = "tcp -h 127.0.0.1 -p 10006";
public static void main(String[] args) {
//ice通信器
Ice.Communicator communicator = null;
try {
//初始化ice通信器communicator,可以使用args傳入一下ice初始化的參數如超時時間,線程池大小等
communicator = Ice.Util.initialize(args);
//構建服務端的代理對象 服務端對象標識以 SERVER_NAME:SERVER_ENDPOINT 格式
Ice.ObjectPrx op = communicator.stringToProxy(SERVER_NAME + ":" + SERVER_ENDPOINT);
//檢查通用客戶端代理op 是不是queryServer對象標識符所關聯的ice對象的代理
IServerPrx qp = IServerPrxHelper.checkedCast(op);
if (qp == null) {
throw new Exception("qp == null");
}
//測試發送信息到戶無端
boolean result = qp.request("hello");
// 輸出服務端返回結果
System.out.println("java:client請求結果:" + result + " 時間:" + System.currentTimeMillis());
//創建客戶端服務
Ice.ObjectAdapter adapter = communicator.createObjectAdapter("");
Ice.Identity id = new Identity();
id.name = "client";
id.category = "";
ClientServant clientServant = new ClientServant();
adapter.add(clientServant, id);
adapter.activate();
//客戶端服務設置服務端點
qp.ice_getConnection().setAdapter(adapter);
//設置回調對象
qp.setCallBack(id);
//設置心跳回調
qp.ice_getConnection().setCallback(new Ice.ConnectionCallback() {
@Override
public void heartbeat(Ice.Connection c) {
System.out.println("sn:" + " server heartbeat....");
}
@Override
public void closed(Ice.Connection c) {
System.out.println("sn:" + " " + "closed....");
}
});
// 每30/2 s向對方做心跳
// 客戶端向服務端做心跳 服務端打印服務端的con.setCallback(new Ice.ConnectionCallback()
qp.ice_getConnection().setACM(new Ice.IntOptional(10), new Ice.Optional<Ice.ACMClose>(Ice.ACMClose.CloseOff),
new Ice.Optional<Ice.ACMHeartbeat>(Ice.ACMHeartbeat.HeartbeatAlways));
} catch (Exception e) {
e.printStackTrace();
}
}
}
step5:啓動驗證
啓動server
啓動client
4、spring實現(spring啓動ice)
step1:改造ServerServant(添加@Service註解)同上
step2:改造server 主要防止ice阻塞,所以通過線程處理
package com.zyj.ice.spring.server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author by zyj
* @version V1.0
* @Description:
* @Date 2019/8/6 21:13
*/
@Service
public class IceService implements Runnable{
/**服務名*/
private static final String SERVER_NAME="Hello";
/**服務端點*/
private static final String SERVER_ENDPOINT="tcp -p 10006";
@Autowired
private HelloServant helloServant;
@PostConstruct
private void startIceServer() {
//構造線程池啓動當前任務
LinkedBlockingQueue<Runnable> runnableList=new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor threadPoolExecutor= new ThreadPoolExecutor(100,100,1L, TimeUnit.SECONDS,runnableList);
threadPoolExecutor.execute(this);
}
@Override
public void run() {
//ice通信器
Ice.Communicator communicator = null;
try {
//初始化ice通信器communicator,可以使用args傳入一下ice初始化的參數如超時時間,線程池大小等
communicator = Ice.Util.initialize();
//創建一個名爲queryEmployeeAdapter的適配器並且默認使用tcp協議 服務部署在10.4.30.81機器上 服務開啓10006監聽端口
Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints(SERVER_NAME,SERVER_ENDPOINT);
// 將servant與ice對象標識符建立映射關係,並添加到ice對象適配器中
adapter.add(helloServant, Ice.Util.stringToIdentity(SERVER_NAME));
// 激活對象適配器
adapter.activate();
System.out.println("服務啓動");
// 服務在退出之前一直保持監聽狀態
communicator.waitForShutdown();
} catch (Exception e) {
e.printStackTrace();
} finally{
//異常銷燬通信器
if(communicator != null){
communicator.destroy();
}
}
}
}
step3:IceClient 實現ClientServant(添加@Service註解)同上
step4:改造客戶端(客戶端連接服務端後,可以保持服務端xxxPrx對象持續調用)
package com.zyj.ice.spring.client;
import Ice.Identity;
import com.zyj.ice.servant.ClientServant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import slice2java.IServerPrx;
import slice2java.IServerPrxHelper;
import javax.annotation.PostConstruct;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author by zyj
* @version V1.0
* @Description:
* @Date 2019/8/6 21:13
*/
@Service
public class IceClient implements Runnable {
/**
* 服務名
*/
private static final String SERVER_NAME = "Hello";
/**
* 服務端點
*/
private static final String SERVER_ENDPOINT = "tcp -h 127.0.0.1 -p 10006";
@Autowired
private ClientServant clientServant;
@PostConstruct
private void startIceClient() {
//構造線程啓動客戶端
LinkedBlockingQueue<Runnable> runnableList = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100, 100, 1L, TimeUnit.SECONDS, runnableList);
threadPoolExecutor.execute(this);
}
@Override
public void run() {
//ice通信器
Ice.Communicator communicator = null;
try {
//初始化ice通信器communicator,可以使用args傳入一下ice初始化的參數如超時時間,線程池大小等
communicator = Ice.Util.initialize();
//構建服務端的代理對象 服務端對象標識以 SERVER_NAME:SERVER_ENDPOINT 格式
Ice.ObjectPrx op = communicator.stringToProxy(SERVER_NAME + ":" + SERVER_ENDPOINT);
//檢查通用客戶端代理op 是不是queryServer對象標識符所關聯的ice對象的代理
IServerPrx qp = IServerPrxHelper.checkedCast(op);
if (qp == null) {
throw new Exception("qp == null");
}
//測試發送信息到戶無端
boolean result = qp.request("hello");
// 輸出服務端返回結果
System.out.println("spring:client請求結果:" + result + " 時間:" + System.currentTimeMillis());
//創建客戶端服務
Ice.ObjectAdapter adapter = communicator.createObjectAdapter("");
Ice.Identity id = new Identity();
id.name = "client";
id.category = "";
adapter.add(clientServant, id);
adapter.activate();
//客戶端服務設置服務端點
qp.ice_getConnection().setAdapter(adapter);
//設置回調對象
qp.setCallBack(id);
//設置心跳回調
qp.ice_getConnection().setCallback(new Ice.ConnectionCallback() {
@Override
public void heartbeat(Ice.Connection c) {
System.out.println("sn:" + " server heartbeat....");
}
@Override
public void closed(Ice.Connection c) {
System.out.println("sn:" + " " + "closed....");
}
});
// 每30/2 s向對方做心跳
// 客戶端向服務端做心跳 服務端打印服務端的con.setCallback(new Ice.ConnectionCallback()
qp.ice_getConnection().setACM(new Ice.IntOptional(10), new Ice.Optional<Ice.ACMClose>(Ice.ACMClose.CloseOff),
new Ice.Optional<Ice.ACMHeartbeat>(Ice.ACMHeartbeat.HeartbeatAlways));
} catch (Exception e) {
e.printStackTrace();
}
}
}
step:5: 啓動