From d1bec90bd0272d42236575c8ff97f313495a6a3d Mon Sep 17 00:00:00 2001 From: "chen.ma" Date: Fri, 12 Nov 2021 23:33:56 +0800 Subject: [PATCH] =?UTF-8?q?Feature:=20=E8=A1=A5=E5=85=85=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E5=AE=9E=E4=BE=8B=E6=B3=A8=E5=86=8C=E4=BF=A1=E6=81=AF?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/config/DiscoveryConfig.java | 22 +- .../DynamicThreadPoolAutoConfiguration.java | 27 ++- .../starter/config/UtilAutoConfiguration.java | 24 ++ .../threadpool/starter/core/ClientWorker.java | 9 +- .../starter/core/ThreadPoolConfigService.java | 7 +- .../starter/toolkit/inet/InetUtils.java | 217 ++++++++++++++++++ .../toolkit/inet/InetUtilsProperties.java | 108 +++++++++ 7 files changed, 397 insertions(+), 17 deletions(-) create mode 100644 hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/UtilAutoConfiguration.java create mode 100644 hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtils.java create mode 100644 hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtilsProperties.java diff --git a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DiscoveryConfig.java b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DiscoveryConfig.java index 6edf4764..0d9548f3 100644 --- a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DiscoveryConfig.java +++ b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DiscoveryConfig.java @@ -1,8 +1,11 @@ package com.github.dynamic.threadpool.starter.config; +import cn.hutool.core.util.StrUtil; import com.github.dynamic.threadpool.common.model.InstanceInfo; +import com.github.dynamic.threadpool.common.toolkit.ContentUtil; import com.github.dynamic.threadpool.starter.core.DiscoveryClient; import com.github.dynamic.threadpool.starter.remote.HttpAgent; +import com.github.dynamic.threadpool.starter.toolkit.inet.InetUtils; import lombok.AllArgsConstructor; import lombok.SneakyThrows; import org.springframework.context.annotation.Bean; @@ -10,7 +13,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import java.net.InetAddress; -import static com.github.dynamic.threadpool.common.constant.Constants.CLIENT_IDENTIFICATION_VALUE; import static com.github.dynamic.threadpool.starter.toolkit.CloudCommonIdUtil.getDefaultInstanceId; import static com.github.dynamic.threadpool.starter.toolkit.CloudCommonIdUtil.getIpApplicationName; @@ -23,7 +25,11 @@ import static com.github.dynamic.threadpool.starter.toolkit.CloudCommonIdUtil.ge @AllArgsConstructor public class DiscoveryConfig { - private ConfigurableEnvironment environment; + private final ConfigurableEnvironment environment; + + private final BootstrapProperties properties; + + private final InetUtils inetUtils; @Bean @SneakyThrows @@ -32,16 +38,22 @@ public class DiscoveryConfig { instanceInfo.setInstanceId(getDefaultInstanceId(environment)) .setIpApplicationName(getIpApplicationName(environment)) .setHostName(InetAddress.getLocalHost().getHostAddress()) - .setIdentify(CLIENT_IDENTIFICATION_VALUE) + .setGroupKey(properties.getItemId() + "+" + properties.getNamespace()) .setAppName(environment.getProperty("spring.application.name")) - .setClientBasePath(environment.getProperty("server.servlet.context-path")); + .setClientBasePath(environment.getProperty("server.servlet.context-path")) + .setGroupKey(ContentUtil.getGroupKey(properties.getItemId(), properties.getNamespace())); String callBackUrl = new StringBuilder().append(instanceInfo.getHostName()).append(":") .append(environment.getProperty("server.port")).append(instanceInfo.getClientBasePath()) .toString(); - instanceInfo.setCallBackUrl(callBackUrl); + String ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + String port = environment.getProperty("server.port"); + String identification = StrUtil.builder(ip, ":", port).toString(); + instanceInfo.setIdentify(identification); + + return instanceInfo; } diff --git a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DynamicThreadPoolAutoConfiguration.java b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DynamicThreadPoolAutoConfiguration.java index a1c5b7e4..2f83c381 100644 --- a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DynamicThreadPoolAutoConfiguration.java +++ b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/DynamicThreadPoolAutoConfiguration.java @@ -1,11 +1,16 @@ package com.github.dynamic.threadpool.starter.config; +import cn.hutool.core.util.StrUtil; import com.github.dynamic.threadpool.common.config.ApplicationContextHolder; import com.github.dynamic.threadpool.starter.controller.PoolRunStateController; -import com.github.dynamic.threadpool.starter.core.*; +import com.github.dynamic.threadpool.starter.core.ConfigService; +import com.github.dynamic.threadpool.starter.core.DynamicThreadPoolPostProcessor; +import com.github.dynamic.threadpool.starter.core.ThreadPoolConfigService; +import com.github.dynamic.threadpool.starter.core.ThreadPoolOperation; import com.github.dynamic.threadpool.starter.enable.MarkerConfiguration; import com.github.dynamic.threadpool.starter.handler.DynamicThreadPoolBannerHandler; import com.github.dynamic.threadpool.starter.remote.HttpAgent; +import com.github.dynamic.threadpool.starter.toolkit.inet.InetUtils; import lombok.AllArgsConstructor; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -14,6 +19,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.core.env.ConfigurableEnvironment; /** * DynamicTp auto configuration. @@ -25,11 +31,21 @@ import org.springframework.core.annotation.Order; @AllArgsConstructor @ConditionalOnBean(MarkerConfiguration.Marker.class) @EnableConfigurationProperties(BootstrapProperties.class) -@ImportAutoConfiguration({HttpClientConfig.class, DiscoveryConfig.class, MessageAlarmConfig.class}) +@ImportAutoConfiguration( + { + HttpClientConfig.class, + DiscoveryConfig.class, + MessageAlarmConfig.class, + UtilAutoConfiguration.class, + CorsConfig.class + } +) public class DynamicThreadPoolAutoConfiguration { private final BootstrapProperties properties; + private final ConfigurableEnvironment environment; + @Bean public DynamicThreadPoolBannerHandler threadPoolBannerHandler() { return new DynamicThreadPoolBannerHandler(properties); @@ -43,8 +59,11 @@ public class DynamicThreadPoolAutoConfiguration { @Bean @SuppressWarnings("all") - public ConfigService configService(HttpAgent httpAgent) { - return new ThreadPoolConfigService(httpAgent); + public ConfigService configService(HttpAgent httpAgent, InetUtils inetUtils) { + String ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + String port = environment.getProperty("server.port"); + String identification = StrUtil.builder(ip, ":", port).toString(); + return new ThreadPoolConfigService(httpAgent, identification); } @Bean diff --git a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/UtilAutoConfiguration.java b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/UtilAutoConfiguration.java new file mode 100644 index 00000000..90e7adf3 --- /dev/null +++ b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/config/UtilAutoConfiguration.java @@ -0,0 +1,24 @@ +package com.github.dynamic.threadpool.starter.config; + +import com.github.dynamic.threadpool.starter.toolkit.inet.InetUtils; +import com.github.dynamic.threadpool.starter.toolkit.inet.InetUtilsProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * Util auto configuration. + * + * @author Spencer Gibb + * @date 2021/11/12 21:34 + */ +@EnableConfigurationProperties(InetUtilsProperties.class) +public class UtilAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public InetUtils inetUtils(InetUtilsProperties properties) { + return new InetUtils(properties); + } + +} diff --git a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ClientWorker.java b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ClientWorker.java index db8f19cf..5560183a 100644 --- a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ClientWorker.java +++ b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ClientWorker.java @@ -36,6 +36,8 @@ public class ClientWorker { private final HttpAgent agent; + private final String identification; + private final ScheduledExecutorService executor; private final ScheduledExecutorService executorService; @@ -45,8 +47,9 @@ public class ClientWorker { private final ConcurrentHashMap cacheMap = new ConcurrentHashMap(16); @SuppressWarnings("all") - public ClientWorker(HttpAgent httpAgent) { + public ClientWorker(HttpAgent httpAgent, String identification) { this.agent = httpAgent; + this.identification = identification; this.timeout = CONFIG_LONG_POLL_TIMEOUT; this.executor = Executors.newScheduledThreadPool(1, r -> { @@ -144,7 +147,7 @@ public class ClientWorker { sb.append(cacheData.tpId).append(WORD_SEPARATOR); sb.append(cacheData.itemId).append(WORD_SEPARATOR); sb.append(cacheData.tenantId).append(WORD_SEPARATOR); - sb.append(CLIENT_IDENTIFICATION_VALUE).append(WORD_SEPARATOR); + sb.append(identification).append(WORD_SEPARATOR); sb.append(cacheData.getMd5()).append(LINE_SEPARATOR); if (cacheData.isInitializing()) { @@ -163,7 +166,7 @@ public class ClientWorker { headers.put(LONG_PULLING_TIMEOUT, "" + timeout); // 确认客户端身份, 修改线程池配置时可单独修改 - headers.put(LONG_PULLING_CLIENT_IDENTIFICATION, CLIENT_IDENTIFICATION_VALUE); + headers.put(LONG_PULLING_CLIENT_IDENTIFICATION, identification); // told server do not hang me up if new initializing cacheData added in if (isInitializingCacheList) { diff --git a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ThreadPoolConfigService.java b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ThreadPoolConfigService.java index 1f840cad..ea4d73a8 100644 --- a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ThreadPoolConfigService.java +++ b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/core/ThreadPoolConfigService.java @@ -12,13 +12,10 @@ import java.util.Arrays; */ public class ThreadPoolConfigService implements ConfigService { - private final HttpAgent httpAgent; - private final ClientWorker clientWorker; - public ThreadPoolConfigService(HttpAgent httpAgent) { - this.httpAgent = httpAgent; - clientWorker = new ClientWorker(httpAgent); + public ThreadPoolConfigService(HttpAgent httpAgent, String identification) { + clientWorker = new ClientWorker(httpAgent, identification); } @Override diff --git a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtils.java b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtils.java new file mode 100644 index 00000000..a435344b --- /dev/null +++ b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtils.java @@ -0,0 +1,217 @@ +package com.github.dynamic.threadpool.starter.toolkit.inet; + +import com.github.dynamic.threadpool.starter.toolkit.thread.ThreadPoolBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.Closeable; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * Inet utils. + * + * @author Spencer Gibb + * @date 2021/11/12 21:33 + */ +public class InetUtils implements Closeable { + + private final ExecutorService executorService; + + private final InetUtilsProperties properties; + + private final Log log = LogFactory.getLog(InetUtils.class); + + public InetUtils(InetUtilsProperties properties) { + this.properties = properties; + this.executorService = ThreadPoolBuilder.builder() + .threadFactory(InetUtilsProperties.PREFIX, Boolean.TRUE) + .corePoolSize(1) + .build(); + } + + @Override + public void close() { + this.executorService.shutdown(); + } + + public HostInfo findFirstNonLoopbackHostInfo() { + InetAddress address = findFirstNonLoopbackAddress(); + if (address != null) { + return convertAddress(address); + } + HostInfo hostInfo = new HostInfo(); + hostInfo.setHostname(this.properties.getDefaultHostname()); + hostInfo.setIpAddress(this.properties.getDefaultIpAddress()); + return hostInfo; + } + + public InetAddress findFirstNonLoopbackAddress() { + InetAddress result = null; + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface + .getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + this.log.trace("Testing interface: " + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || result == null) { + lowest = ifc.getIndex(); + } else if (result != null) { + continue; + } + + // @formatter:off + if (!ignoreInterface(ifc.getDisplayName())) { + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements(); ) { + InetAddress address = addrs.nextElement(); + if (address instanceof Inet4Address + && !address.isLoopbackAddress() + && isPreferredAddress(address)) { + this.log.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + } + // @formatter:on + } + } + } catch (IOException ex) { + this.log.error("Cannot get first non-loopback address", ex); + } + + if (result != null) { + return result; + } + + try { + return InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + this.log.warn("Unable to retrieve localhost"); + } + + return null; + } + + boolean isPreferredAddress(InetAddress address) { + + if (this.properties.isUseOnlySiteLocalInterfaces()) { + final boolean siteLocalAddress = address.isSiteLocalAddress(); + if (!siteLocalAddress) { + this.log.trace("Ignoring address: " + address.getHostAddress()); + } + return siteLocalAddress; + } + final List preferredNetworks = this.properties.getPreferredNetworks(); + if (preferredNetworks.isEmpty()) { + return true; + } + for (String regex : preferredNetworks) { + final String hostAddress = address.getHostAddress(); + if (hostAddress.matches(regex) || hostAddress.startsWith(regex)) { + return true; + } + } + this.log.trace("Ignoring address: " + address.getHostAddress()); + return false; + } + + boolean ignoreInterface(String interfaceName) { + for (String regex : this.properties.getIgnoredInterfaces()) { + if (interfaceName.matches(regex)) { + this.log.trace("Ignoring interface: " + interfaceName); + return true; + } + } + return false; + } + + public HostInfo convertAddress(final InetAddress address) { + HostInfo hostInfo = new HostInfo(); + Future result = this.executorService.submit(address::getHostName); + + String hostname; + try { + hostname = result.get(this.properties.getTimeoutSeconds(), TimeUnit.SECONDS); + } catch (Exception e) { + this.log.info("Cannot determine local hostname"); + hostname = "localhost"; + } + hostInfo.setHostname(hostname); + hostInfo.setIpAddress(address.getHostAddress()); + return hostInfo; + } + + /** + * Host information pojo. + */ + public static class HostInfo { + + /** + * Should override the host info. + */ + public boolean override; + + private String ipAddress; + + private String hostname; + + public HostInfo(String hostname) { + this.hostname = hostname; + } + + public HostInfo() { + } + + public int getIpAddressAsInt() { + InetAddress inetAddress = null; + String host = this.ipAddress; + if (host == null) { + host = this.hostname; + } + try { + inetAddress = InetAddress.getByName(host); + } catch (final UnknownHostException e) { + throw new IllegalArgumentException(e); + } + return ByteBuffer.wrap(inetAddress.getAddress()).getInt(); + } + + public boolean isOverride() { + return this.override; + } + + public void setOverride(boolean override) { + this.override = override; + } + + public String getIpAddress() { + return this.ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getHostname() { + return this.hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + } + +} diff --git a/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtilsProperties.java b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtilsProperties.java new file mode 100644 index 00000000..2605f1e4 --- /dev/null +++ b/hippo4j-spring-boot-starter/src/main/java/com/github/dynamic/threadpool/starter/toolkit/inet/InetUtilsProperties.java @@ -0,0 +1,108 @@ +package com.github.dynamic.threadpool.starter.toolkit.inet; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +/** + * Inet utils properties. + * + * @author chen.ma + * @date 2021/11/12 21:34 + */ +@ConfigurationProperties(InetUtilsProperties.PREFIX) +public class InetUtilsProperties { + + /** + * Prefix for the Inet Utils properties. + */ + public static final String PREFIX = "spring.cloud.inetutils"; + + /** + * The default hostname. Used in case of errors. + */ + private String defaultHostname = "localhost"; + + /** + * The default IP address. Used in case of errors. + */ + private String defaultIpAddress = "127.0.0.1"; + + /** + * Timeout, in seconds, for calculating hostname. + */ + @Value("${spring.util.timeout.sec:${SPRING_UTIL_TIMEOUT_SEC:1}}") + private int timeoutSeconds = 1; + + /** + * List of Java regular expressions for network interfaces that will be ignored. + */ + private List ignoredInterfaces = new ArrayList<>(); + + /** + * Whether to use only interfaces with site local addresses. See + * {@link InetAddress#isSiteLocalAddress()} for more details. + */ + private boolean useOnlySiteLocalInterfaces = false; + + /** + * List of Java regular expressions for network addresses that will be preferred. + */ + private List preferredNetworks = new ArrayList<>(); + + public static String getPREFIX() { + return PREFIX; + } + + public String getDefaultHostname() { + return this.defaultHostname; + } + + public void setDefaultHostname(String defaultHostname) { + this.defaultHostname = defaultHostname; + } + + public String getDefaultIpAddress() { + return this.defaultIpAddress; + } + + public void setDefaultIpAddress(String defaultIpAddress) { + this.defaultIpAddress = defaultIpAddress; + } + + public int getTimeoutSeconds() { + return this.timeoutSeconds; + } + + public void setTimeoutSeconds(int timeoutSeconds) { + this.timeoutSeconds = timeoutSeconds; + } + + public List getIgnoredInterfaces() { + return this.ignoredInterfaces; + } + + public void setIgnoredInterfaces(List ignoredInterfaces) { + this.ignoredInterfaces = ignoredInterfaces; + } + + public boolean isUseOnlySiteLocalInterfaces() { + return this.useOnlySiteLocalInterfaces; + } + + public void setUseOnlySiteLocalInterfaces(boolean useOnlySiteLocalInterfaces) { + this.useOnlySiteLocalInterfaces = useOnlySiteLocalInterfaces; + } + + public List getPreferredNetworks() { + return this.preferredNetworks; + } + + public void setPreferredNetworks(List preferredNetworks) { + this.preferredNetworks = preferredNetworks; + } + +}