目的:创建代表消费者服务或应用程序发送网络请求的帮助服务。
使用场景:大使适用于无法修改或极难修改的旧式远程服务。 可以在客户端上实现连接性的功能,而无需更改远程服务。
1.创建远程服务和大使服务共享的接口
interface RemoteServiceInterface {
long doRemoteFunction(int value);
}
2.创建单例的远程服务
public class RemoteService implements RemoteServiceInterface {
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class.getName());
private static RemoteService service=null;
static synchronized RemoteService getRemoteService(){
if (service==null){
service=new RemoteService();
}
return service;
}
public RemoteService() {
}
@Override
public long doRemoteFunction(int value) {
long waitTime = (long) Math.floor(Math.random() * 1000);
try {
Thread.sleep(waitTime);
} catch (InterruptedException e) {
LOGGER.error("Thread sleep interrupted",e);
}
return waitTime>=200?value*10:-1;
}
}
3.创建大使代理,增加日志和延迟检测的额外功能
// 状态枚举
public enum RemoteServiceStatus {
FAILURE(-1);
private final long remoteServiceStatusValue;
public long getRemoteServiceStatusValue() {
return remoteServiceStatusValue;
}
RemoteServiceStatus(long remoteServiceStatusValue) {
this.remoteServiceStatusValue = remoteServiceStatusValue;
}
}
@Slf4j
public class ServiceAmbassador implements RemoteServiceInterface {
private static final int RETRIES = 3;
private static final int DELAY_MS = 3000;
public ServiceAmbassador() {
}
@Override
public long doRemoteFunction(int value) throws Exception {
return safeCall(value);
}
/**
* 检查时延
* @param value
* @return
*/
private long checkLatency(int value) {
long startTime = System.currentTimeMillis();
long result = RemoteService.getRemoteService().doRemoteFunction(value);
long timeTaken = System.currentTimeMillis() - startTime;
log.info("Time taken (ms) :{}", timeTaken);
return result;
}
/**
* 安全呼叫
* @param value
* @return
*/
private long safeCall(int value) {
long retries = 0;
long result = FAILURE.getRemoteServiceStatusValue();
for (int i = 0; i < RETRIES; i++) {
//重试次数大于3,返回失败码
if (retries >= RETRIES) {
return FAILURE.getRemoteServiceStatusValue();
}
//失败记录+1
if ((result = checkLatency(value)) == FAILURE.getRemoteServiceStatusValue()) {
log.info("Failed to reach remote:({})", i + 1);
retries++;
try {
Thread.sleep(DELAY_MS);
} catch (InterruptedException e) {
log.error("Thread sleep state interrupted", e);
Thread.currentThread().interrupt();
}
} else {
break;
}
}
return result;
}
}
4.创建客户端,具有用于与远程服务进行交互的本地服务大使
@Slf4j
public class Client {
private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador();
@SneakyThrows
long useService(int value) {
long result = serviceAmbassador.doRemoteFunction(value);
log.info("Service result:{}", result);
return result;
}
}
5.测试
Client c1 = new Client();
Client c2 = new Client();
c1.useService(12);
c2.useService(73);
输出:
Time taken (ms) :15
Failed to reach remote:(1)
Time taken (ms) :221
Service result:120
Time taken (ms) :234
Service result:730