diff --git a/solon-projects/solon-server/solon-server-feathttp/pom.xml b/solon-projects/solon-server/solon-server-feathttp/pom.xml
index d702ad3be5df22d22a55e48e4bd9b67d4fb2ee48..76e5bef3b5a887c46353d99d10b843f6340eb02a 100644
--- a/solon-projects/solon-server/solon-server-feathttp/pom.xml
+++ b/solon-projects/solon-server/solon-server-feathttp/pom.xml
@@ -33,6 +33,12 @@
${feat-core.version}
+
+ org.slf4j
+ jul-to-slf4j
+ ${slf4j.version}
+
+
org.noear
solon-test
diff --git a/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java b/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java
index 26a9ba70c863fb7d50ed4b1cc9d0d3a55b451d54..63f409fec639e25628da9754fd749d06c0306f05 100644
--- a/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java
+++ b/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java
@@ -15,6 +15,10 @@
*/
package org.noear.solon.server.feathttp.integration;
+import java.util.Enumeration;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
import org.noear.solon.Solon;
import org.noear.solon.Utils;
import org.noear.solon.core.*;
@@ -28,103 +32,169 @@ import org.noear.solon.server.prop.impl.HttpServerProps;
import org.noear.solon.server.prop.impl.WebSocketServerProps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.slf4j.bridge.SLF4JBridgeHandler;
/**
* @author airhead
*/
public final class FeatHttpPlugin implements Plugin {
- static final Logger log = LoggerFactory.getLogger(FeatHttpPlugin.class);
-
- private static Signal _signal;
- private FeatHttpServerComb _server;
-
- public static Signal signal() {
- return _signal;
+ static final Logger log = LoggerFactory.getLogger(FeatHttpPlugin.class);
+
+ /** feat-core 中使用 LoggerFactory.getLogger() 的所有类(基于 feat-core 2.1.0)。 升级 feat-core 版本时需同步检查此清单。 */
+ private static final String[] FEAT_LOGGER_CLASSES = {
+ "tech.smartboot.feat.core.client.HttpRestImpl",
+ "tech.smartboot.feat.core.client.WebSocketClient",
+ "tech.smartboot.feat.core.common.FeatUtils",
+ "tech.smartboot.feat.core.server.handler.HttpStaticResourceHandler",
+ "tech.smartboot.feat.core.server.impl.Endpoint",
+ "tech.smartboot.feat.core.server.impl.HttpEndpoint",
+ "tech.smartboot.feat.core.server.impl.HttpMessageProcessor",
+ "tech.smartboot.feat.core.server.impl.HttpRequestProtocol",
+ "tech.smartboot.feat.core.server.upgrade.http2.Http2Session",
+ "tech.smartboot.feat.core.server.upgrade.websocket.WebSocketResponseImpl",
+ "tech.smartboot.feat.core.server.upgrade.websocket.WebSocketUpgrade",
+ "tech.smartboot.feat.router.Router",
+ "tech.smartboot.feat.router.session.LocalSessionManager",
+ };
+
+ private static Signal _signal;
+ private FeatHttpServerComb _server;
+
+ public static Signal signal() {
+ return _signal;
+ }
+
+ public static String solon_server_ver() {
+ return "FeatHttp 2.1/" + Solon.version();
+ }
+
+ @Override
+ public void start(AppContext context) throws Throwable {
+ if (context.app().enableHttp() == false) {
+ return;
}
- public static String solon_server_ver() {
- return "FeatHttp 2.1/" + Solon.version();
+ if (context.isStarted()) {
+ start0(context);
+ } else {
+ context.lifecycle(
+ ServerConstants.SIGNAL_LIFECYCLE_INDEX,
+ new LifecycleBean() {
+ @Override
+ public void postStart() throws Throwable {
+ start0(context);
+ }
+ });
}
+ }
- @Override
- public void start(AppContext context) throws Throwable {
- if (context.app().enableHttp() == false) {
- return;
- }
+ @Override
+ public void stop() throws Throwable {
+ if (_server != null) {
+ _server.stop();
+ _server = null;
- if (context.isStarted()) {
- start0(context);
- } else {
- context.lifecycle(ServerConstants.SIGNAL_LIFECYCLE_INDEX, new LifecycleBean() {
- @Override
- public void postStart() throws Throwable {
- start0(context);
- }
- });
- }
+ log.info("Server:main: feat: Has Stopped (" + solon_server_ver() + ")");
}
+ }
- @Override
- public void stop() throws Throwable {
- if (_server != null) {
- _server.stop();
- _server = null;
-
- log.info("Server:main: feat: Has Stopped (" + solon_server_ver() + ")");
- }
- }
+ private void start0(AppContext context) throws Throwable {
+ installJulBridge();
- private void start0(AppContext context) throws Throwable {
- //初始化属性
- ServerProps.init();
- MultipartUtil.init();
+ // 初始化属性
+ ServerProps.init();
+ MultipartUtil.init();
- HttpServerProps props = new HttpServerProps();
- final String _host = props.getHost();
- final int _port = props.getPort();
- final String _name = props.getName();
+ HttpServerProps props = new HttpServerProps();
+ final String _host = props.getHost();
+ final int _port = props.getPort();
+ final String _name = props.getName();
- long time_start = System.currentTimeMillis();
+ long time_start = System.currentTimeMillis();
+ _server = new FeatHttpServerComb(props);
+ _server.enableWebSocket(context.app().enableWebSocket());
+ _server.setCoreThreads(props.getCoreThreads());
- _server = new FeatHttpServerComb(props);
- _server.enableWebSocket(context.app().enableWebSocket());
- _server.setCoreThreads(props.getCoreThreads());
+ if (props.isIoBound()) {
+ // 如果是io密集型的,加二段线程池
+ _server.setExecutor(props.newWorkExecutor("feat-"));
+ }
- if (props.isIoBound()) {
- //如果是io密集型的,加二段线程池
- _server.setExecutor(props.newWorkExecutor("feat-"));
- }
+ _server.setHandler(context.app()::tryHandle);
- _server.setHandler(context.app()::tryHandle);
+ // 尝试事件扩展
+ EventBus.publish(_server);
+ _server.start(_host, _port);
- //尝试事件扩展
- EventBus.publish(_server);
- _server.start(_host, _port);
+ final String _wrapHost = props.getWrapHost();
+ final int _wrapPort = props.getWrapPort();
+ _signal = new SignalSim(_name, _wrapHost, _wrapPort, "http", SignalType.HTTP);
+ context.app().signalAdd(_signal);
+ long time_end = System.currentTimeMillis();
- final String _wrapHost = props.getWrapHost();
- final int _wrapPort = props.getWrapPort();
- _signal = new SignalSim(_name, _wrapHost, _wrapPort, "http", SignalType.HTTP);
- context.app().signalAdd(_signal);
+ String connectorInfo =
+ "solon.connector:main: feat: Started ServerConnector@{HTTP/1.1,[http/1.1]";
+ if (context.app().enableWebSocket()) {
+ // 有名字定义时,添加信号注册
+ WebSocketServerProps wsProps = WebSocketServerProps.getInstance();
+ if (Utils.isNotEmpty(wsProps.getName())) {
+ SignalSim wsSignal =
+ new SignalSim(wsProps.getName(), _wrapHost, _wrapPort, "ws", SignalType.WEBSOCKET);
+ context.app().signalAdd(wsSignal);
+ }
- long time_end = System.currentTimeMillis();
+ String wsServerUrl = props.buildWsServerUrl(_server.isSecure());
+ log.info(connectorInfo + "[WebSocket]}{" + wsServerUrl + "}");
+ }
- String connectorInfo = "solon.connector:main: feat: Started ServerConnector@{HTTP/1.1,[http/1.1]";
- if (context.app().enableWebSocket()) {
- //有名字定义时,添加信号注册
- WebSocketServerProps wsProps = WebSocketServerProps.getInstance();
- if (Utils.isNotEmpty(wsProps.getName())) {
- SignalSim wsSignal = new SignalSim(wsProps.getName(), _wrapHost, _wrapPort, "ws", SignalType.WEBSOCKET);
- context.app().signalAdd(wsSignal);
- }
+ String httpServerUrl = props.buildHttpServerUrl(_server.isSecure());
+ log.info(connectorInfo + "}{" + httpServerUrl + "}");
+ log.info(
+ "Server:main: feat: Started ("
+ + solon_server_ver()
+ + ") @"
+ + (time_end - time_start)
+ + "ms");
+ }
+
+ /** 1.将 SLF4JBridgeHandler 安装到 JUL root logger,2.预热所有 feat-core logger 并桥接到 SLF4J */
+ private void installJulBridge() {
+ System.setProperty("feat.log.level", "ALL");
+ SLF4JBridgeHandler.removeHandlersForRootLogger();
+ SLF4JBridgeHandler.install();
+
+ bridgeFeatLoggers();
+ }
+
+ /** 桥接 feat-core RunLogger 创建的 JUL logger:移除原有 handler,打开 parent 传播。 */
+ private void bridgeFeatLoggers() {
+ // 预热 feat-core 所有使用 LoggerFactory 的 logger
+ for (String className : FEAT_LOGGER_CLASSES) {
+ tech.smartboot.feat.core.common.logging.LoggerFactory.getLogger(className);
+ }
- String wsServerUrl = props.buildWsServerUrl(_server.isSecure());
- log.info(connectorInfo + "[WebSocket]}{" + wsServerUrl + "}");
+ LogManager manager = LogManager.getLogManager();
+ Enumeration names = manager.getLoggerNames();
+ while (names.hasMoreElements()) {
+ String name = names.nextElement();
+ if (name != null && name.startsWith("tech.smartboot.feat")) {
+ java.util.logging.Logger julLogger = manager.getLogger(name);
+ if (julLogger != null) {
+ Handler[] handlers = julLogger.getHandlers();
+ if (handlers == null || handlers.length == 0) {
+ continue;
+ }
+
+ for (Handler h : handlers) {
+ julLogger.removeHandler(h);
+ }
+
+ julLogger.setUseParentHandlers(true);
+ julLogger.setLevel(Level.ALL);
}
-
- String httpServerUrl = props.buildHttpServerUrl(_server.isSecure());
- log.info(connectorInfo + "}{" + httpServerUrl + "}");
- log.info("Server:main: feat: Started (" + solon_server_ver() + ") @" + (time_end - time_start) + "ms");
+ }
}
-}
\ No newline at end of file
+ }
+}