Bruceyan/issue#1106 (#1125)

* Refactor the web adapter module to be compatible with Spring Boot 1.x versions.

* fix: Prevent NPE exceptions from being thrown when certain parameters are not configured.

* fix: Add some ERROR logs.

* fix: Add some notes.
pull/1127/head
yanrongzhen 1 year ago committed by GitHub
parent a3724dd093
commit 9f94d9d29a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,14 +17,14 @@
package cn.hippo4j.adapter.web;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
import org.springframework.context.ApplicationContext;
import java.util.concurrent.Executor;
/**
@ -33,6 +33,12 @@ import java.util.concurrent.Executor;
@Slf4j
public abstract class AbstractWebThreadPoolService implements WebThreadPoolService, ApplicationRunner {
private final IWebThreadPoolHandlerSupport support;
public AbstractWebThreadPoolService(IWebThreadPoolHandlerSupport support) {
this.support = support;
}
/**
* Thread pool executor
*/
@ -41,17 +47,16 @@ public abstract class AbstractWebThreadPoolService implements WebThreadPoolServi
/**
* Get web thread pool by server
*
* @param webServer
* @return
*/
protected abstract Executor getWebThreadPoolByServer(WebServer webServer);
protected abstract Executor getWebThreadPoolInternal();
@Override
public Executor getWebThreadPool() {
if (executor == null) {
synchronized (AbstractWebThreadPoolService.class) {
if (executor == null) {
executor = getWebThreadPoolByServer(getWebServer());
executor = getWebThreadPoolInternal();
}
}
}
@ -59,16 +64,37 @@ public abstract class AbstractWebThreadPoolService implements WebThreadPoolServi
}
@Override
public WebServer getWebServer() {
ApplicationContext applicationContext = ApplicationContextHolder.getInstance();
WebServer webServer = ((WebServerApplicationContext) applicationContext).getWebServer();
return webServer;
public ThreadPoolBaseInfo simpleInfo() {
return support.simpleInfo();
}
@Override
public ThreadPoolParameter getWebThreadPoolParameter() {
return support.getWebThreadPoolParameter();
}
@Override
public ThreadPoolRunStateInfo getWebRunStateInfo() {
return support.getWebRunStateInfo();
}
@Override
public void updateWebThreadPool(ThreadPoolParameterInfo threadPoolParameterInfo) {
support.updateWebThreadPool(threadPoolParameterInfo);
}
@Override
public WebContainerEnum getWebContainerType() {
return support.getWebContainerType();
}
/**
* Call-back after the web container has been started.
*/
@Override
public void run(ApplicationArguments args) {
try {
getWebThreadPool();
this.support.setExecutor(getWebThreadPool());
} catch (Exception ignored) {
}
}

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web;
import cn.hippo4j.common.config.ApplicationContextHolder;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
import org.springframework.context.ApplicationContext;
import java.util.concurrent.Executor;
/**
* Default WebThreadPoolService abstract class,
* reuses common capabilities for web container operations.
*/
public abstract class DefaultAbstractWebThreadPoolService extends AbstractWebThreadPoolService {
public DefaultAbstractWebThreadPoolService(IWebThreadPoolHandlerSupport support) {
super(support);
}
/**
* Get the internal abstract method of the web container thread pool,
* to be implemented by subclasses.
* @return
*/
@Override
protected Executor getWebThreadPoolInternal() {
return getWebThreadPoolByServer(getWebServer());
}
/**
* Get port by server.
* @return web port
*/
@Override
public Integer getPort() {
return getWebServer().getPort();
}
/**
* Get the thread pool object of the current web container based on the WebServer.
* @param webServer current Web-Server.
* @return Thread pool executor of the current web container.
*/
protected abstract Executor getWebThreadPoolByServer(WebServer webServer);
/**
* Get current Web Server.
* @return webServer current Web-Server.
*/
public WebServer getWebServer() {
ApplicationContext applicationContext = ApplicationContextHolder.getInstance();
return ((WebServerApplicationContext) applicationContext).getWebServer();
}
}

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import java.util.concurrent.Executor;
/**
* Support class for WebThreadPoolHandler, providing some common methods.
*/
public interface IWebThreadPoolHandlerSupport {
/**
* Set the Executor to the current class
* so that other methods in the class can function properly.
* @param executor
*/
void setExecutor(Executor executor);
/**
* Retrieve the simple information of the thread pool.
* @return
*/
ThreadPoolBaseInfo simpleInfo();
/**
* Retrieve the parameter of the thread pool.
* @return
*/
ThreadPoolParameter getWebThreadPoolParameter();
/**
* Retrieve the run state of the thread pool.
* @return
*/
ThreadPoolRunStateInfo getWebRunStateInfo();
/**
* Update thread pool parameters.
* @param threadPoolParameterInfo New parameters
*/
void updateWebThreadPool(ThreadPoolParameterInfo threadPoolParameterInfo);
WebContainerEnum getWebContainerType();
}

@ -23,7 +23,6 @@ import cn.hippo4j.common.toolkit.Assert;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.core.toolkit.inet.InetUtils;
import lombok.NoArgsConstructor;
import org.springframework.boot.web.server.WebServer;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.Arrays;
@ -86,8 +85,7 @@ public class WebIpAndPortHolder {
WebThreadPoolHandlerChoose webThreadPoolHandlerChoose = ApplicationContextHolder.getBean(WebThreadPoolHandlerChoose.class);
WebThreadPoolService webThreadPoolService = webThreadPoolHandlerChoose.choose();
// When get the port at startup, can get the message: "port xxx was already in use" or use two ports
WebServer webServer = webThreadPoolService.getWebServer();
port = webServer.getPort();
port = webThreadPoolService.getPort();
}
return new WebIpAndPortInfo(ip, String.valueOf(port));

@ -17,6 +17,7 @@
package cn.hippo4j.adapter.web;
import cn.hippo4j.adapter.web.WebThreadPoolService;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.web.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;

@ -22,7 +22,6 @@ import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import org.springframework.boot.web.server.WebServer;
import java.util.concurrent.Executor;
@ -38,6 +37,12 @@ public interface WebThreadPoolService {
*/
Executor getWebThreadPool();
/**
* Get web container port.
* @return
*/
Integer getPort();
/**
* Simple info.
*
@ -66,15 +71,6 @@ public interface WebThreadPoolService {
*/
void updateWebThreadPool(ThreadPoolParameterInfo threadPoolParameterInfo);
/**
* Get web server.
*
* @return
*/
default WebServer getWebServer() {
return null;
}
/**
* resolve current web container type.
*

@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web.jetty;
import cn.hippo4j.adapter.web.DefaultAbstractWebThreadPoolService;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.common.constant.ChangeThreadPoolConstants;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
import org.springframework.boot.web.server.WebServer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
/**
* Jetty web thread pool handler.
*/
@Slf4j
public class DefaultJettyWebThreadPoolHandler extends DefaultAbstractWebThreadPoolService
implements
JettyWebThreadPoolHandlerAdapt {
public DefaultJettyWebThreadPoolHandler() {
super(new JettyWebThreadPoolHandlerSupport());
}
/**
* Get the thread pool object of the current web container based on the WebServer.
* @param webServer current Web-Server.
* @return Thread pool executor of the current web container.
*/
@Override
protected Executor getWebThreadPoolByServer(WebServer webServer) {
JettyWebServer jettyWebServer = (JettyWebServer) webServer;
return jettyWebServer.getServer().getThreadPool();
}
}

@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web.jetty;
import cn.hippo4j.adapter.web.WebThreadPoolService;
/**
* Adapt interface of Jetty web thread-pool handler.
*/
public interface JettyWebThreadPoolHandlerAdapt extends WebThreadPoolService {
}

@ -15,8 +15,9 @@
* limitations under the License.
*/
package cn.hippo4j.adapter.web;
package cn.hippo4j.adapter.web.jetty;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.common.constant.ChangeThreadPoolConstants;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
@ -26,22 +27,26 @@ import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
import org.springframework.boot.web.server.WebServer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
/**
* Jetty web thread pool handler.
* The supporting class for WebThreadPoolHandler,
* which facilitates the creation of a Jetty web container.
*/
@Slf4j
public class JettyWebThreadPoolHandler extends AbstractWebThreadPoolService {
public class JettyWebThreadPoolHandlerSupport implements IWebThreadPoolHandlerSupport {
private Executor executor;
/**
* A callback will be invoked and the Executor will be set up when the web container has been started.
* @param executor Thread-pool executor in Jetty container.
*/
@Override
protected Executor getWebThreadPoolByServer(WebServer webServer) {
JettyWebServer jettyWebServer = (JettyWebServer) webServer;
return jettyWebServer.getServer().getThreadPool();
public void setExecutor(Executor executor) {
this.executor = executor;
}
@Override

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web.tomcat;
import cn.hippo4j.adapter.web.DefaultAbstractWebThreadPoolService;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.core.executor.state.AbstractThreadPoolRuntime;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Tomcat web thread pool handler.
*/
@Slf4j
public class DefaultTomcatWebThreadPoolHandler extends DefaultAbstractWebThreadPoolService
implements
TomcatWebThreadPoolHandlerAdapt {
private final AtomicBoolean cacheFlag = new AtomicBoolean(Boolean.FALSE);
private static String exceptionMessage;
public DefaultTomcatWebThreadPoolHandler(AbstractThreadPoolRuntime runtime) {
super(new TomcatWebThreadPoolHandlerSupport(runtime));
}
/**
* Get the thread pool object of the current web container based on the WebServer.
* @param webServer current Web-Server.
* @return Thread pool executor of the current web container.
*/
@Override
protected Executor getWebThreadPoolByServer(WebServer webServer) {
if (cacheFlag.get()) {
log.warn("Exception getting Tomcat thread pool. Exception message: {}", exceptionMessage);
return null;
}
Executor tomcatExecutor = null;
try {
tomcatExecutor = ((TomcatWebServer) webServer).getTomcat().getConnector().getProtocolHandler().getExecutor();
} catch (Exception ex) {
cacheFlag.set(Boolean.TRUE);
exceptionMessage = ex.getMessage();
log.error("Failed to get Tomcat thread pool. Message: {}", exceptionMessage);
}
return tomcatExecutor;
}
}

@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web.tomcat;
import cn.hippo4j.adapter.web.WebThreadPoolService;
/**
* Adapt interface of Tomcat web thread-pool handler.
*/
public interface TomcatWebThreadPoolHandlerAdapt extends WebThreadPoolService {
}

@ -15,8 +15,9 @@
* limitations under the License.
*/
package cn.hippo4j.adapter.web;
package cn.hippo4j.adapter.web.tomcat;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.common.constant.ChangeThreadPoolConstants;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
@ -25,10 +26,7 @@ import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.CalculateUtil;
import cn.hippo4j.core.executor.state.AbstractThreadPoolRuntime;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@ -36,36 +34,29 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Tomcat web thread pool handler.
* The supporting class for WebThreadPoolHandler,
* which facilitates the creation of a Tomcat web container.
*/
@Slf4j
@RequiredArgsConstructor
public class TomcatWebThreadPoolHandler extends AbstractWebThreadPoolService {
public class TomcatWebThreadPoolHandlerSupport implements IWebThreadPoolHandlerSupport {
private final AtomicBoolean cacheFlag = new AtomicBoolean(Boolean.FALSE);
private final AbstractThreadPoolRuntime runtime;
private static String exceptionMessage;
private Executor executor;
private final AbstractThreadPoolRuntime webThreadPoolRunStateHandler;
public TomcatWebThreadPoolHandlerSupport(AbstractThreadPoolRuntime runtime) {
this.runtime = runtime;
}
/**
* A callback will be invoked and the Executor will be set up when the web container has been started.
* @param executor Thread-pool executor in Tomcat container.
*/
@Override
protected Executor getWebThreadPoolByServer(WebServer webServer) {
if (cacheFlag.get()) {
log.warn("Exception getting Tomcat thread pool. Exception message: {}", exceptionMessage);
return null;
}
Executor tomcatExecutor = null;
try {
tomcatExecutor = ((TomcatWebServer) webServer).getTomcat().getConnector().getProtocolHandler().getExecutor();
} catch (Exception ex) {
cacheFlag.set(Boolean.TRUE);
exceptionMessage = ex.getMessage();
log.error("Failed to get Tomcat thread pool. Message: {}", exceptionMessage);
}
return tomcatExecutor;
public void setExecutor(Executor executor) {
this.executor = executor;
}
@Override
@ -110,7 +101,7 @@ public class TomcatWebThreadPoolHandler extends AbstractWebThreadPoolService {
@Override
public ThreadPoolRunStateInfo getWebRunStateInfo() {
if (executor instanceof ThreadPoolExecutor) {
return webThreadPoolRunStateHandler.getPoolRunState(null, executor);
return runtime.getPoolRunState(null, executor);
}
ThreadPoolRunStateInfo runStateInfo = new ThreadPoolRunStateInfo();
org.apache.tomcat.util.threads.ThreadPoolExecutor tomcatThreadPoolExecutor = (org.apache.tomcat.util.threads.ThreadPoolExecutor) executor;
@ -144,7 +135,7 @@ public class TomcatWebThreadPoolHandler extends AbstractWebThreadPoolService {
String rejectedExecutionHandlerName = executor instanceof ThreadPoolExecutor ? ((ThreadPoolExecutor) executor).getRejectedExecutionHandler().getClass().getSimpleName()
: tomcatThreadPoolExecutor.getRejectedExecutionHandler().getClass().getSimpleName();
runStateInfo.setRejectedName(rejectedExecutionHandlerName);
return webThreadPoolRunStateHandler.supplement(runStateInfo);
return runtime.supplement(runStateInfo);
}
@Override

@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web.undertow;
import java.lang.reflect.Field;
import java.util.Objects;
import java.util.concurrent.Executor;
import cn.hippo4j.adapter.web.DefaultAbstractWebThreadPoolService;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import io.undertow.Undertow;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.util.ReflectionUtils;
/**
* Undertow web thread pool handler.
*/
@Slf4j
public class DefaultUndertowWebThreadPoolHandler extends DefaultAbstractWebThreadPoolService
implements
UndertowWebThreadPoolHandlerAdapt {
private static final String UNDERTOW_NAME = "undertow";
public DefaultUndertowWebThreadPoolHandler() {
super(new UndertowWebThreadPoolHandlerSupport());
}
/**
* Get the thread pool object of the current web container based on the WebServer.
* @param webServer current Web-Server.
* @return Thread pool executor of the current web container.
*/
@Override
protected Executor getWebThreadPoolByServer(WebServer webServer) {
// There is no need to consider reflection performance because the fetch is a singleton.
// Springboot 2-3 version, can directly through reflection to obtain the undertow property
UndertowServletWebServer undertowServletWebServer = (UndertowServletWebServer) webServer;
Field undertowField = ReflectionUtils.findField(UndertowServletWebServer.class, UNDERTOW_NAME);
ReflectionUtils.makeAccessible(undertowField);
Undertow undertow = (Undertow) ReflectionUtils.getField(undertowField, undertowServletWebServer);
return Objects.isNull(undertow) ? null : undertow.getWorker();
}
}

@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.web.undertow;
import cn.hippo4j.adapter.web.WebThreadPoolService;
/**
* Adapt interface of Undertow web thread-pool handler.
*/
public interface UndertowWebThreadPoolHandlerAdapt extends WebThreadPoolService {
}

@ -15,15 +15,9 @@
* limitations under the License.
*/
package cn.hippo4j.adapter.web;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.concurrent.Executor;
package cn.hippo4j.adapter.web.undertow;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.common.constant.ChangeThreadPoolConstants;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
@ -32,33 +26,33 @@ import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.CalculateUtil;
import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
import io.undertow.Undertow;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import org.xnio.Options;
import org.xnio.XnioWorker;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executor;
/**
* Undertow web thread pool handler.
* The supporting class for WebThreadPoolHandler,
* which facilitates the creation of a Undertow web container.
*/
@Slf4j
public class UndertowWebThreadPoolHandler extends AbstractWebThreadPoolService {
public class UndertowWebThreadPoolHandlerSupport implements IWebThreadPoolHandlerSupport {
private static final String UNDERTOW_NAME = "undertow";
private Executor executor;
/**
* A callback will be invoked and the Executor will be set up when the web container has been started.
* @param executor Thread-pool executor in Undertow container.
*/
@Override
protected Executor getWebThreadPoolByServer(WebServer webServer) {
// There is no need to consider reflection performance because the fetch is a singleton.
// Springboot 2-3 version, can directly through reflection to obtain the undertow property
UndertowServletWebServer undertowServletWebServer = (UndertowServletWebServer) webServer;
Field undertowField = ReflectionUtils.findField(UndertowServletWebServer.class, UNDERTOW_NAME);
ReflectionUtils.makeAccessible(undertowField);
Undertow undertow = (Undertow) ReflectionUtils.getField(undertowField, undertowServletWebServer);
return Objects.isNull(undertow) ? null : undertow.getWorker();
public void setExecutor(Executor executor) {
this.executor = executor;
}
@Override

@ -22,5 +22,20 @@
<artifactId>hippo4j-config-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.config.springboot1x.starter.config;
import cn.hippo4j.adapter.web.*;
import cn.hippo4j.adapter.web.WebThreadPoolRunStateHandler;
import cn.hippo4j.config.springboot1x.starter.web.jetty.JettyWebThreadPoolHandler1x;
import cn.hippo4j.config.springboot1x.starter.web.tomcat.TomcatWebThreadPoolHandler1x;
import cn.hippo4j.config.springboot1x.starter.web.undertow.UndertowWebThreadPoolHandler1x;
import cn.hippo4j.springboot.starter.adapter.web.WebThreadPoolHandlerConfiguration;
import io.undertow.Undertow;
import org.apache.catalina.Loader;
import org.apache.catalina.Server;
import org.apache.catalina.startup.Tomcat;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.xnio.SslClientAuthMode;
import javax.servlet.Servlet;
/**
* Spring auto-configuration class for WebThreadPoolHandlers.
*/
@Configuration
@AutoConfigureBefore(WebThreadPoolHandlerConfiguration.class)
public class WebThreadPoolHandlerConfiguration1x {
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})
@ConditionalOnMissingBean(value = WebThreadPoolService.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
/**
* Nested configuration if Tomcat is being used.
*/
@Bean
public WebThreadPoolService tomcatWebThreadPoolHandler(WebThreadPoolRunStateHandler webThreadPoolRunStateHandler) {
return new TomcatWebThreadPoolHandler1x(webThreadPoolRunStateHandler);
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration
@ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})
@ConditionalOnMissingBean(value = WebThreadPoolService.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {
@Bean
public WebThreadPoolService jettyWebThreadPoolHandler() {
return new JettyWebThreadPoolHandler1x();
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})
@ConditionalOnMissingBean(value = WebThreadPoolService.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {
@Bean
public WebThreadPoolService undertowWebThreadPoolHandler() {
return new UndertowWebThreadPoolHandler1x();
}
}
}

@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.config.springboot1x.starter.web;
import cn.hippo4j.adapter.web.AbstractWebThreadPoolService;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.common.config.ApplicationContextHolder;
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
/**
* Abstract class for adapting WebThreadPoolService to Spring 1.x version.
*/
public abstract class AbstractWebThreadPoolService1x extends AbstractWebThreadPoolService {
public AbstractWebThreadPoolService1x(IWebThreadPoolHandlerSupport support) {
super(support);
}
/**
* Get the embedded Servlet container from the Spring application context.
*/
protected EmbeddedServletContainer getContainer() {
return ((EmbeddedWebApplicationContext) ApplicationContextHolder.getInstance()).getEmbeddedServletContainer();
}
/**
* Get the port from web container.
*/
@Override
public Integer getPort() {
return getContainer().getPort();
}
}

@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.config.springboot1x.starter.web.jetty;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.adapter.web.jetty.JettyWebThreadPoolHandlerSupport;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.web.exception.ServiceException;
import cn.hippo4j.config.springboot1x.starter.web.AbstractWebThreadPoolService1x;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainer;
import java.util.concurrent.Executor;
/**
* WebThreadPoolHandler compatible with Jetty container for Spring 1.x version.
*/
@Slf4j
public class JettyWebThreadPoolHandler1x extends AbstractWebThreadPoolService1x {
public JettyWebThreadPoolHandler1x() {
super(new JettyWebThreadPoolHandlerSupport());
}
@Override
protected Executor getWebThreadPoolInternal() {
try {
return ((JettyEmbeddedServletContainer) getContainer()).getServer().getThreadPool();
} catch (Throwable th) {
log.error("Failed to get Jetty thread pool.", th);
return null;
}
}
}

@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.config.springboot1x.starter.web.tomcat;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.adapter.web.tomcat.TomcatWebThreadPoolHandlerSupport;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.web.exception.ServiceException;
import cn.hippo4j.config.springboot1x.starter.web.AbstractWebThreadPoolService1x;
import cn.hippo4j.core.executor.state.AbstractThreadPoolRuntime;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer;
import java.util.concurrent.Executor;
/**
* WebThreadPoolHandler compatible with Tomcat container for Spring 1.x version.
*/
@Slf4j
public class TomcatWebThreadPoolHandler1x extends AbstractWebThreadPoolService1x {
public TomcatWebThreadPoolHandler1x(AbstractThreadPoolRuntime runtime) {
super(new TomcatWebThreadPoolHandlerSupport(runtime));
}
@Override
protected Executor getWebThreadPoolInternal() {
try {
return ((TomcatEmbeddedServletContainer) getContainer())
.getTomcat().getConnector().getProtocolHandler().getExecutor();
} catch (Throwable th) {
log.error("Failed to get Tomcat thread pool.", th);
return null;
}
}
}

@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.config.springboot1x.starter.web.undertow;
import cn.hippo4j.adapter.web.IWebThreadPoolHandlerSupport;
import cn.hippo4j.adapter.web.undertow.UndertowWebThreadPoolHandlerSupport;
import cn.hippo4j.common.enums.WebContainerEnum;
import cn.hippo4j.common.model.ThreadPoolBaseInfo;
import cn.hippo4j.common.model.ThreadPoolParameter;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.web.exception.ServiceException;
import cn.hippo4j.config.springboot1x.starter.web.AbstractWebThreadPoolService1x;
import io.undertow.Undertow;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainer;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.concurrent.Executor;
/**
* WebThreadPoolHandler compatible with Undertow container for Spring 1.x version.
*/
@Slf4j
public class UndertowWebThreadPoolHandler1x extends AbstractWebThreadPoolService1x {
private static final String UNDERTOW_NAME = "undertow";
public UndertowWebThreadPoolHandler1x() {
super(new UndertowWebThreadPoolHandlerSupport());
}
@Override
protected Executor getWebThreadPoolInternal() {
try {
UndertowEmbeddedServletContainer container = (UndertowEmbeddedServletContainer) getContainer();
Field field = ReflectionUtils.findField(UndertowEmbeddedServletContainer.class, UNDERTOW_NAME);
ReflectionUtils.makeAccessible(field);
Undertow undertow = (Undertow) ReflectionUtils.getField(field, container);
return undertow.getWorker();
} catch (Throwable th) {
log.error("Failed to get Undertow thread pool.", th);
return null;
}
}
}

@ -1 +1,3 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hippo4j.config.springboot1x.starter.config.ConfigHandlerAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.hippo4j.config.springboot1x.starter.config.ConfigHandlerAutoConfiguration,\
cn.hippo4j.config.springboot1x.starter.config.WebThreadPoolHandlerConfiguration1x

@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import java.util.Objects;
import java.util.Optional;
import static cn.hippo4j.config.springboot.starter.refresher.event.Hippo4jConfigDynamicRefreshEventOrder.WEB_EXECUTOR_LISTENER;
@ -55,6 +56,17 @@ public class WebExecutorRefreshListener extends AbstractRefreshListener<WebThrea
WebThreadPoolHandlerChoose webThreadPoolHandlerChoose = ApplicationContextHolder.getBean(WebThreadPoolHandlerChoose.class);
WebThreadPoolService webThreadPoolService = webThreadPoolHandlerChoose.choose();
ThreadPoolParameter beforeParameter = webThreadPoolService.getWebThreadPoolParameter();
// Prevent NPE exceptions from being thrown when certain parameters are not configured.
if (nowParameter.getCoreSize() == null) {
nowParameter.setCoreSize(beforeParameter.getCoreSize());
}
if (nowParameter.getMaxSize() == null) {
nowParameter.setMaxSize(beforeParameter.getMaxSize());
}
if (nowParameter.getKeepAliveTime() == null) {
nowParameter.setKeepAliveTime(beforeParameter.getKeepAliveTime());
}
if (!Objects.equals(beforeParameter.getCoreSize(), nowParameter.getCoreSize())
|| !Objects.equals(beforeParameter.getMaxSize(), nowParameter.getMaxSize())
|| !Objects.equals(beforeParameter.getKeepAliveTime(), nowParameter.getKeepAliveTime())) {

@ -17,10 +17,13 @@
package cn.hippo4j.springboot.starter.adapter.web;
import cn.hippo4j.adapter.web.JettyWebThreadPoolHandler;
import cn.hippo4j.adapter.web.TomcatWebThreadPoolHandler;
import cn.hippo4j.adapter.web.UndertowWebThreadPoolHandler;
import cn.hippo4j.adapter.web.jetty.DefaultJettyWebThreadPoolHandler;
import cn.hippo4j.adapter.web.jetty.JettyWebThreadPoolHandlerAdapt;
import cn.hippo4j.adapter.web.tomcat.DefaultTomcatWebThreadPoolHandler;
import cn.hippo4j.adapter.web.tomcat.TomcatWebThreadPoolHandlerAdapt;
import cn.hippo4j.adapter.web.undertow.DefaultUndertowWebThreadPoolHandler;
import cn.hippo4j.adapter.web.WebThreadPoolRunStateHandler;
import cn.hippo4j.adapter.web.undertow.UndertowWebThreadPoolHandlerAdapt;
import io.undertow.Undertow;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.UpgradeProtocol;
@ -29,6 +32,7 @@ import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
@ -49,6 +53,7 @@ public class WebThreadPoolHandlerConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
@ConditionalOnBean(value = ConfigurableTomcatWebServerFactory.class, search = SearchStrategy.CURRENT)
@ConditionalOnMissingBean({DefaultTomcatWebThreadPoolHandler.class, TomcatWebThreadPoolHandlerAdapt.class})
static class EmbeddedTomcat {
/**
@ -57,14 +62,15 @@ public class WebThreadPoolHandlerConfiguration {
* the Web embedded server loads the {@link ServletWebServerFactory} top-level interface type at the same time
*/
@Bean
public TomcatWebThreadPoolHandler tomcatWebThreadPoolHandler(WebThreadPoolRunStateHandler webThreadPoolRunStateHandler) {
return new TomcatWebThreadPoolHandler(webThreadPoolRunStateHandler);
public TomcatWebThreadPoolHandlerAdapt tomcatWebThreadPoolHandler(WebThreadPoolRunStateHandler webThreadPoolRunStateHandler) {
return new DefaultTomcatWebThreadPoolHandler(webThreadPoolRunStateHandler);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})
@ConditionalOnBean(value = ConfigurableJettyWebServerFactory.class, search = SearchStrategy.CURRENT)
@ConditionalOnMissingBean({DefaultJettyWebThreadPoolHandler.class, JettyWebThreadPoolHandlerAdapt.class})
static class EmbeddedJetty {
/**
@ -73,14 +79,15 @@ public class WebThreadPoolHandlerConfiguration {
* the Web embedded server loads the {@link ServletWebServerFactory} top-level interface type at the same time
*/
@Bean
public JettyWebThreadPoolHandler jettyWebThreadPoolHandler() {
return new JettyWebThreadPoolHandler();
public JettyWebThreadPoolHandlerAdapt jettyWebThreadPoolHandler() {
return new DefaultJettyWebThreadPoolHandler();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})
@ConditionalOnBean(value = ConfigurableUndertowWebServerFactory.class, search = SearchStrategy.CURRENT)
@ConditionalOnMissingBean({DefaultUndertowWebThreadPoolHandler.class, UndertowWebThreadPoolHandlerAdapt.class})
static class EmbeddedUndertow {
/**
@ -89,8 +96,8 @@ public class WebThreadPoolHandlerConfiguration {
* the Web embedded server loads the {@link ServletWebServerFactory} top-level interface type at the same time
*/
@Bean
public UndertowWebThreadPoolHandler undertowWebThreadPoolHandler() {
return new UndertowWebThreadPoolHandler();
public UndertowWebThreadPoolHandlerAdapt undertowWebThreadPoolHandler() {
return new DefaultUndertowWebThreadPoolHandler();
}
}
}

Loading…
Cancel
Save