diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/pom.xml b/hippo4j-spring-boot/hippo4j-spring-boot-starter/pom.xml
index 4aba794b..81e12dd3 100644
--- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/pom.xml
+++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/pom.xml
@@ -26,6 +26,20 @@
spring-boot-starter-web
+
+ org.springframework.boot
+ spring-boot-starter-jetty
+ compile
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+ compile
+ true
+
+
+
com.squareup.okhttp3
okhttp
diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/config/DynamicThreadPoolAutoConfiguration.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/config/DynamicThreadPoolAutoConfiguration.java
index a3381fe8..30ae05f0 100644
--- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/config/DynamicThreadPoolAutoConfiguration.java
+++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/config/DynamicThreadPoolAutoConfiguration.java
@@ -17,9 +17,7 @@ import cn.hippo4j.starter.event.ApplicationContentPostProcessor;
import cn.hippo4j.starter.handler.BaseThreadDetailStateHandler;
import cn.hippo4j.starter.handler.DynamicThreadPoolBannerHandler;
import cn.hippo4j.starter.handler.ThreadPoolRunStateHandler;
-import cn.hippo4j.starter.handler.web.TomcatWebThreadPoolHandler;
-import cn.hippo4j.starter.handler.web.WebThreadPoolHandlerChoose;
-import cn.hippo4j.starter.handler.web.WebThreadPoolRunStateHandler;
+import cn.hippo4j.starter.handler.web.*;
import cn.hippo4j.starter.monitor.ReportingEventExecutor;
import cn.hippo4j.starter.monitor.collect.RunTimeInfoCollector;
import cn.hippo4j.starter.monitor.send.HttpConnectSender;
@@ -28,13 +26,11 @@ import cn.hippo4j.starter.remote.HttpAgent;
import cn.hippo4j.starter.remote.HttpScheduledHealthCheck;
import cn.hippo4j.starter.remote.ServerHealthCheck;
import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@@ -55,6 +51,12 @@ import org.springframework.core.env.ConfigurableEnvironment;
@ImportAutoConfiguration({HttpClientConfiguration.class, DiscoveryConfiguration.class, MessageNotifyConfiguration.class, UtilAutoConfiguration.class})
public class DynamicThreadPoolAutoConfiguration {
+ private static final String TOMCAT_SERVLET_WEB_SERVER_FACTORY = "tomcatWebThreadPoolHandler";
+
+ private static final String JETTY_SERVLET_WEB_SERVER_FACTORY = "JettyServletWebServerFactory";
+
+ private static final String UNDERTOW_SERVLET_WEB_SERVER_FACTORY = "undertowServletWebServerFactory";
+
private final BootstrapProperties properties;
private final ConfigurableEnvironment environment;
@@ -143,11 +145,23 @@ public class DynamicThreadPoolAutoConfiguration {
}
@Bean
- @ConditionalOnBean(name = "tomcatServletWebServerFactory")
- public TomcatWebThreadPoolHandler tomcatWebThreadPoolHandler(@Autowired(required = false) ServletWebServerApplicationContext applicationContext) {
- return new TomcatWebThreadPoolHandler(applicationContext);
+ @ConditionalOnBean(name = TOMCAT_SERVLET_WEB_SERVER_FACTORY)
+ public TomcatWebThreadPoolHandler tomcatWebThreadPoolHandler() {
+ return new TomcatWebThreadPoolHandler();
+ }
+
+ @Bean
+ @ConditionalOnBean(name = JETTY_SERVLET_WEB_SERVER_FACTORY)
+ public JettyWebThreadPoolHandler jettyWebThreadPoolHandler() {return new JettyWebThreadPoolHandler();
}
+ @Bean
+ @ConditionalOnBean(name = UNDERTOW_SERVLET_WEB_SERVER_FACTORY)
+ public UndertowWebThreadPoolHandler undertowWebThreadPoolHandler() {
+ return new UndertowWebThreadPoolHandler();
+ }
+
+
@Bean
public WebThreadPoolHandlerChoose webThreadPoolServiceChoose() {
return new WebThreadPoolHandlerChoose();
diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/AbstractWebThreadPoolService.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/AbstractWebThreadPoolService.java
index 8a0560c0..c2297edd 100644
--- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/AbstractWebThreadPoolService.java
+++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/AbstractWebThreadPoolService.java
@@ -1,5 +1,14 @@
package cn.hippo4j.starter.handler.web;
+import cn.hippo4j.common.config.ApplicationContextHolder;
+import cn.hippo4j.common.model.PoolParameterInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.web.context.WebServerApplicationContext;
+import org.springframework.boot.web.server.WebServer;
+import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationListener;
+
import java.util.concurrent.Executor;
/**
@@ -8,6 +17,7 @@ import java.util.concurrent.Executor;
* @author chen.ma
* @date 2022/1/19 21:20
*/
+@Slf4j
public abstract class AbstractWebThreadPoolService implements WebThreadPoolService {
/**
@@ -20,14 +30,18 @@ public abstract class AbstractWebThreadPoolService implements WebThreadPoolServi
*
* @return
*/
- protected abstract Executor getWebThreadPoolByServer();
+ protected abstract Executor getWebThreadPoolByServer(WebServer webServer);
+
+
@Override
public Executor getWebThreadPool() {
if (executor == null) {
synchronized (AbstractWebThreadPoolService.class) {
+ ApplicationContext applicationContext = ApplicationContextHolder.getInstance();
+ WebServer webServer = ((WebServerApplicationContext) applicationContext).getWebServer();
if (executor == null) {
- executor = getWebThreadPoolByServer();
+ executor = getWebThreadPoolByServer(webServer);
}
}
}
diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/JettyWebThreadPoolHandler.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/JettyWebThreadPoolHandler.java
new file mode 100644
index 00000000..e5b7ab9c
--- /dev/null
+++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/JettyWebThreadPoolHandler.java
@@ -0,0 +1,51 @@
+package cn.hippo4j.starter.handler.web;
+
+import cn.hippo4j.common.model.PoolParameterInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.web.embedded.jetty.JettyWebServer;
+import org.springframework.boot.web.server.WebServer;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author : wh
+ * @date : 2022/2/28 16:55
+ * @description:
+ */
+@Slf4j
+public class JettyWebThreadPoolHandler extends AbstractWebThreadPoolService{
+
+
+
+ @Override
+ protected Executor getWebThreadPoolByServer(WebServer webServer) {
+ JettyWebServer jettyWebServer = (JettyWebServer) webServer;
+ return jettyWebServer.getServer().getThreadPool();
+ }
+
+ @Override
+ public void updateWebThreadPool(PoolParameterInfo poolParameterInfo) {
+ try {
+ ThreadPoolExecutor jettyExecutor = (ThreadPoolExecutor) executor;
+ int originalCoreSize = jettyExecutor.getCorePoolSize();
+ int originalMaximumPoolSize = jettyExecutor.getMaximumPoolSize();
+ long originalKeepAliveTime = jettyExecutor.getKeepAliveTime(TimeUnit.SECONDS);
+
+ jettyExecutor.setCorePoolSize(poolParameterInfo.getCoreSize());
+ jettyExecutor.setMaximumPoolSize(poolParameterInfo.getMaxSize());
+ jettyExecutor.setKeepAliveTime(poolParameterInfo.getKeepAliveTime(), TimeUnit.SECONDS);
+
+ log.info(
+ "🔥 Changed web thread pool. coreSize :: [{}], maxSize :: [{}], keepAliveTime :: [{}]",
+ String.format("%s => %s", originalCoreSize, poolParameterInfo.getCoreSize()),
+ String.format("%s => %s", originalMaximumPoolSize, poolParameterInfo.getMaxSize()),
+ String.format("%s => %s", originalKeepAliveTime, poolParameterInfo.getKeepAliveTime())
+ );
+ } catch (Exception ex) {
+ log.error("Failed to modify the jetty thread pool parameter.", ex);
+ }
+
+ }
+}
diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/TomcatWebThreadPoolHandler.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/TomcatWebThreadPoolHandler.java
index 8229d08e..b01e1cb7 100644
--- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/TomcatWebThreadPoolHandler.java
+++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/TomcatWebThreadPoolHandler.java
@@ -4,7 +4,7 @@ import cn.hippo4j.common.model.PoolParameterInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
-import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
+import org.springframework.boot.web.server.WebServer;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@@ -19,16 +19,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
@Slf4j
@AllArgsConstructor
-public class TomcatWebThreadPoolHandler extends AbstractWebThreadPoolService {
+public class TomcatWebThreadPoolHandler extends AbstractWebThreadPoolService{
- private final ServletWebServerApplicationContext applicationContext;
private final AtomicBoolean cacheFlag = new AtomicBoolean(Boolean.FALSE);
private static String EXCEPTION_MESSAGE;
@Override
- protected Executor getWebThreadPoolByServer() {
+ protected Executor getWebThreadPoolByServer(WebServer webServer) {
if (cacheFlag.get()) {
log.warn("Exception getting Tomcat thread pool. Exception message :: {}", EXCEPTION_MESSAGE);
return null;
@@ -36,7 +35,7 @@ public class TomcatWebThreadPoolHandler extends AbstractWebThreadPoolService {
Executor tomcatExecutor = null;
try {
- tomcatExecutor = ((TomcatWebServer) applicationContext.getWebServer()).getTomcat().getConnector().getProtocolHandler().getExecutor();
+ tomcatExecutor = ((TomcatWebServer) webServer).getTomcat().getConnector().getProtocolHandler().getExecutor();
} catch (Exception ex) {
cacheFlag.set(Boolean.TRUE);
EXCEPTION_MESSAGE = ex.getMessage();
diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/UndertowWebThreadPoolHandler.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/UndertowWebThreadPoolHandler.java
index 9861f37d..4ac1f15f 100644
--- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/UndertowWebThreadPoolHandler.java
+++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/starter/handler/web/UndertowWebThreadPoolHandler.java
@@ -1,10 +1,19 @@
package cn.hippo4j.starter.handler.web;
import cn.hippo4j.common.model.PoolParameterInfo;
+import io.undertow.Undertow;
import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.web.embedded.undertow.UndertowWebServer;
+import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
+import org.springframework.util.ReflectionUtils;
+import java.lang.reflect.Field;
+import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
/**
* Undertow web thread pool handler.
@@ -12,18 +21,45 @@ import java.util.concurrent.Executor;
* @author chen.ma
* @date 2022/1/19 21:19
*/
-@AllArgsConstructor
+@Slf4j
public class UndertowWebThreadPoolHandler extends AbstractWebThreadPoolService {
- private final ServletWebServerApplicationContext applicationContext;
+ private static final String UNDERTOW_NAME = "undertow";
+
+
@Override
- protected Executor getWebThreadPoolByServer() {
- return null;
+ protected Executor getWebThreadPoolByServer(WebServer webServer) {
+ // There is no need to consider reflection performance because the fetch is a singleton
+ UndertowWebServer undertowWebServer = (UndertowWebServer) webServer;
+ Field undertowField = ReflectionUtils.findField(UndertowWebServer.class, UNDERTOW_NAME);
+ assert undertowField != null;
+ ReflectionUtils.makeAccessible(undertowField);
+ Undertow undertow = (Undertow) ReflectionUtils.getField(undertowField, undertowWebServer);
+ return Objects.isNull(undertow) ? null : undertow.getWorker();
}
@Override
public void updateWebThreadPool(PoolParameterInfo poolParameterInfo) {
+ try {
+ ThreadPoolExecutor undertowExecutor = (ThreadPoolExecutor) executor;
+ int originalCoreSize = undertowExecutor.getCorePoolSize();
+ int originalMaximumPoolSize = undertowExecutor.getMaximumPoolSize();
+ long originalKeepAliveTime = undertowExecutor.getKeepAliveTime(TimeUnit.SECONDS);
+
+ undertowExecutor.setCorePoolSize(poolParameterInfo.getCoreSize());
+ undertowExecutor.setMaximumPoolSize(poolParameterInfo.getMaxSize());
+ undertowExecutor.setKeepAliveTime(poolParameterInfo.getKeepAliveTime(), TimeUnit.SECONDS);
+
+ log.info(
+ "🔥 Changed web thread pool. coreSize :: [{}], maxSize :: [{}], keepAliveTime :: [{}]",
+ String.format("%s => %s", originalCoreSize, poolParameterInfo.getCoreSize()),
+ String.format("%s => %s", originalMaximumPoolSize, poolParameterInfo.getMaxSize()),
+ String.format("%s => %s", originalKeepAliveTime, poolParameterInfo.getKeepAliveTime())
+ );
+ } catch (Exception ex) {
+ log.error("Failed to modify the undertow thread pool parameter.", ex);
+ }
}