com.yeskery.nut.cloud.registry.inlay.InlayServerRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nut Show documentation
Show all versions of nut Show documentation
A web mvc framework with runtime environment build on java8
The newest version!
package com.yeskery.nut.cloud.registry.inlay;
import com.yeskery.nut.application.ServerEventContext;
import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.bean.aware.ApplicationContextAware;
import com.yeskery.nut.cloud.registry.core.*;
import com.yeskery.nut.core.*;
import com.yeskery.nut.extend.responsive.ResponsiveConvert;
import com.yeskery.nut.util.StringUtils;
import com.yeskery.nut.util.http.HttpUtils;
import java.security.SecureRandom;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* 默认内置注册器
* @author YESKERY
* 2024/1/4
*/
public class InlayServerRegistry extends DefaultServerRegistry implements ApplicationContextAware {
/** 日志对象 */
private static final Logger logger = Logger.getLogger(InlayServerRegistry.class.getName());
/** 同步Key */
private static final String ASYNC_KEY = "Server-Registry";
/** 同步value */
private static final String ASYNC_VALUE = "InlayServerRegistry";
/** 同步推送uri */
private static final String ASYNC_PUSH_URI = "/inlay-server-registry/async/push";
/** 同步拉取uri */
private static final String ASYNC_PULL_URI = "/inlay-server-registry/async/pull";
/** 服务地址key */
private static final String SERVER_ADDRESS_KEY = "nut.cloud.registry.inlay.uri";
/** 应用上下文 */
private ApplicationContext applicationContext;
/** 定时器 */
private Timer timer;
/** 当前的服务实例 */
private Server server;
/** 服务地址集合 */
private final List serverAddressList = new ArrayList<>();
@Override
public void afterStart(ServerEventContext serverEventContext) {
Environment environment = applicationContext.getBean(Environment.class);
String serverAddress = environment.getEnvProperty(SERVER_ADDRESS_KEY);
if (!StringUtils.isEmpty(serverAddress)) {
List addressList = Arrays.stream(serverAddress.split(","))
.filter(s -> !StringUtils.isEmpty(s)).collect(Collectors.toList());
if (!addressList.isEmpty()) {
serverAddressList.addAll(addressList);
}
}
Server currentServer = registerServer(getCurrentServerMetadata(environment));
currentServer.getServerInstanceRegistry().registerInstance(getCurrentServerInstanceMetadata(environment));
server = currentServer;
ControllerManager controllerManager = serverEventContext.getControllerManager();
controllerManager.registerController(new InlayServerRegistryAsyncPushRequestHandler(applicationContext), Method.PUT, ASYNC_PUSH_URI);
logger.info("InlayServerRegistry: Async Push Endpoint[" + ASYNC_PUSH_URI + "], Alias[], Method[" + Method.PUT + "]");
controllerManager.registerController(new InlayServerRegistryAsyncPullRequestHandler(applicationContext), Method.POST, ASYNC_PULL_URI);
logger.info("InlayServerRegistry: Async Pull Endpoint[" + ASYNC_PULL_URI + "], Alias[], Method[" + Method.POST + "]");
timer = new Timer("inlayServerRegistryAsyncTimer", true);
timer.schedule(new InlayServerAsyncPushTimerTask(applicationContext), 30000, 90000);
timer.schedule(new InlayServerAsyncPullTimerTask(applicationContext), 0, 60000);
}
@Override
public void beforeClose(ServerEventContext serverEventContext) {
super.beforeClose(serverEventContext);
if (timer != null) {
timer.cancel();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
/**
* 默认内置同步推送请求处理类
* @author YESKERY
* 2024/1/5
*/
private class InlayServerRegistryAsyncPushRequestHandler implements RequestHandler {
/** 应用上下文 */
private final ApplicationContext applicationContext;
/**
* 构建默认内置同步推送请求处理类
* @param applicationContext 应用上下文
*/
private InlayServerRegistryAsyncPushRequestHandler(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void handle(Request request, Response response, Execution execution) {
String value = request.getHeader(ASYNC_KEY);
if (StringUtils.isEmpty(value) || !ASYNC_VALUE.equals(value)) {
return;
}
ResponsiveConvert responsiveConvert = applicationContext.getBean(ResponsiveConvert.class);
InlayServersAsync inlayServersAsync = responsiveConvert.convertFromString(request.getBodyAsString(), InlayServersAsync.class);
refreshInlayServersAsync(inlayServersAsync);
}
}
/**
* 默认内置同步拉取请求处理类
* @author YESKERY
* 2024/1/5
*/
private class InlayServerRegistryAsyncPullRequestHandler implements RequestHandler {
/**
* 应用上下文
*/
private final ApplicationContext applicationContext;
/**
* 构建默认内置同步推送请求处理类
*
* @param applicationContext 应用上下文
*/
private InlayServerRegistryAsyncPullRequestHandler(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void handle(Request request, Response response, Execution execution) {
String value = request.getHeader(ASYNC_KEY);
if (StringUtils.isEmpty(value) || !ASYNC_VALUE.equals(value)) {
return;
}
response.writeJson(parseInlayServersAsyncToJson(applicationContext.getBean(ResponsiveConvert.class)));
}
}
/**
* 默认内置同步推送定时任务
* @author YESKERY
* 2024/1/5
*/
private class InlayServerAsyncPushTimerTask extends TimerTask {
/** 要访问的服务大小 */
private static final int ACCESS_SIZE = 3;
/** 随机数 */
private final SecureRandom random = new SecureRandom();
/** 应用上下文 */
private final ApplicationContext applicationContext;
/**
* 构建默认内置同步推送定时任务
* @param applicationContext 应用上下文
*/
private InlayServerAsyncPushTimerTask(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void run() {
List servers = new ArrayList<>(getServerMap().values());
if (servers.isEmpty()) {
return;
}
List accessServers;
if (servers.size() <= ACCESS_SIZE) {
accessServers = servers.stream().filter(r -> r != InlayServerRegistry.this.server)
.collect(Collectors.toList());
} else {
Collections.shuffle(servers, random);
accessServers = servers.stream().filter(r -> r != InlayServerRegistry.this.server)
.limit(ACCESS_SIZE).collect(Collectors.toList());
}
for (Server server : accessServers) {
for (Instance instance : server.getInstances()) {
String url = instance.getScheme() + instance.getIp() + ":" + instance.getPort() + ASYNC_PUSH_URI;
try {
HttpUtils.getDefaultInstance().doPut(url, Collections.singletonList(new NameAndValue(ASYNC_KEY, ASYNC_VALUE)),
parseInlayServersAsyncToJson(applicationContext.getBean(ResponsiveConvert.class)), MediaType.APPLICATION_JSON);
} catch (Exception e) {
logger.logp(Level.INFO, "InlayServerRegistry.InlayServerAsyncPushTimerTask", "run",
"InlayServerRegistryAsync Server[" + server.name() + "], Instance[scheme("
+ instance.getScheme() + "), ip(" + instance.getIp() + "), port(" + instance.getPort()
+ ") Async Push Fail.", e);
}
}
}
}
}
/**
* 默认内置同步拉取定时任务
* @author YESKERY
* 2024/1/5
*/
private class InlayServerAsyncPullTimerTask extends TimerTask {
/** 应用上下文 */
private final ApplicationContext applicationContext;
/**
* 构建默认内置同步拉取定时任务
* @param applicationContext 应用上下文
*/
private InlayServerAsyncPullTimerTask(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void run() {
ResponsiveConvert responsiveConvert = applicationContext.getBean(ResponsiveConvert.class);
for (String serverAddress : serverAddressList) {
try {
String result = HttpUtils.getDefaultInstance().doPostString(serverAddress + ASYNC_PULL_URI,
Collections.singletonList(new NameAndValue(ASYNC_KEY, ASYNC_VALUE)), (String) null, MediaType.APPLICATION_JSON);
if (!StringUtils.isEmpty(result)) {
InlayServersAsync inlayServersAsync = responsiveConvert.convertFromString(result, InlayServersAsync.class);
refreshInlayServersAsync(inlayServersAsync);
}
} catch (Exception e) {
logger.logp(Level.INFO, "InlayServerRegistry.InlayServerAsyncPullTimerTask", "run",
"InlayServerRegistryAsync Server Address[" + serverAddress + " Async Pull Fail.", e);
}
}
}
}
/**
* 转换服务为内置服务同步对象集合对象json
* @param responsiveConvert 响应式转换器
* @return 转换后的服务为内置服务同步对象集合对象json
*/
private String parseInlayServersAsyncToJson(ResponsiveConvert responsiveConvert) {
Collection serverCollection = getServerMap().values();
InlayServersAsync inlayServersAsync = new InlayServersAsync();
List inlayServerAsyncList = new ArrayList<>(serverCollection.size());
for (Server server : serverCollection) {
inlayServerAsyncList.add(parseInlayServerAsync(server));
}
inlayServersAsync.setServers(inlayServerAsyncList);
return responsiveConvert.convertTo(inlayServersAsync);
}
/**
* 转换内置服务同步对象
* @param server 服务对象
* @return 转换后的内置服务同步对象
*/
private InlayServerAsync parseInlayServerAsync(Server server) {
InlayServerAsync inlayServerAsync = new InlayServerAsync();
inlayServerAsync.setName(server.name());
inlayServerAsync.setVersion(server.getMetadata().getVersion());
List inlayServerInstanceAsyncList = parseInlayServerInstanceAsync(server.getInstances());
inlayServerAsync.setInstances(inlayServerInstanceAsyncList);
return inlayServerAsync;
}
/**
* 转换内置服务实例同步对象
* @param instances 服务实例集合
* @return 转换后的内置服务实例同步对象
*/
private List parseInlayServerInstanceAsync(List instances) {
List inlayServerInstanceAsyncList = new ArrayList<>(instances.size());
for (Instance instance : instances) {
InlayServerInstanceAsync inlayServerInstanceAsync = new InlayServerInstanceAsync();
inlayServerInstanceAsync.setIp(instance.getIp());
inlayServerInstanceAsync.setScheme(instance.getScheme());
inlayServerInstanceAsync.setPort(instance.getPort());
inlayServerInstanceAsyncList.add(inlayServerInstanceAsync);
}
return inlayServerInstanceAsyncList;
}
/**
* 刷新内置服务同步对象集合
* @param inlayServersAsync 内置服务同步对象集合
*/
private void refreshInlayServersAsync(InlayServersAsync inlayServersAsync) {
for (InlayServerAsync inlayServerAsync : inlayServersAsync.getServers()) {
String serverName = inlayServerAsync.getName();
Server server = getServer(serverName);
if (server == null) {
DefaultServerMetadata defaultServerMetadata = new DefaultServerMetadata();
defaultServerMetadata.setName(serverName);
defaultServerMetadata.setRegisterTime(System.currentTimeMillis());
defaultServerMetadata.setVersion(inlayServerAsync.getVersion());
defaultServerMetadata.setLatestUpdateTime(defaultServerMetadata.getRegisterTime());
registerServer(defaultServerMetadata);
server = getServer(serverName);
} else {
DefaultServerMetadata defaultServerMetadata = (DefaultServerMetadata) server.getMetadata();
String version;
if ((version = server.getMetadata().getVersion()) != null && version.equals(defaultServerMetadata.getVersion())) {
logger.info("InlayServerRegistryAsync Server[" + serverName + "] Original Version["
+ inlayServerAsync.getVersion() + "] Local Version[" + defaultServerMetadata.getVersion()
+ "] Not Match, Skip Update.");
continue;
}
defaultServerMetadata.setLatestUpdateTime(System.currentTimeMillis());
}
ServerInstanceRegistry serverInstanceRegistry = server.getServerInstanceRegistry();
for (InlayServerInstanceAsync inlayServerInstanceAsync : inlayServerAsync.getInstances()) {
DefaultServerInstanceMetadata defaultServerInstanceMetadata = new DefaultServerInstanceMetadata();
defaultServerInstanceMetadata.setScheme(inlayServerInstanceAsync.getScheme());
defaultServerInstanceMetadata.setIp(inlayServerInstanceAsync.getIp());
defaultServerInstanceMetadata.setPort(inlayServerInstanceAsync.getPort());
if (!serverInstanceRegistry.contains(defaultServerInstanceMetadata)) {
defaultServerInstanceMetadata.setStatus(ServerInstanceStatus.OK);
serverInstanceRegistry.registerInstance(defaultServerInstanceMetadata);
}
}
}
}
}