基于Tomcat的旧Spring MVC应用启动异端口HTTP服务器的适配框架及便捷实现方案咨询
我太懂这种版本冲突的头疼了——在Tomcat上跑的老旧Spring MVC应用要新增一个不同端口的HTTP服务,本来想用顺手的Javalin,结果因为Jetty自带的Servlet 3.1和现有应用的3.0版本撞车了。下面给你几个实用的替代方案,都是能避开版本冲突的:
1. 用Undertow做轻量服务
Undertow是WildFly默认的Web服务器,它的依赖非常干净,完全可以和Servlet 3.0和平共处。你可以只引入Undertow的核心包,不需要带高版本的Servlet API,而且它的路由和请求处理逻辑和Javalin一样便捷。
示例代码:
import io.undertow.Undertow; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.util.Headers; public class MyUndertowServer { public MyUndertowServer() { Undertow server = Undertow.builder() .addHttpListener(7000, "0.0.0.0") .setHandler(exchange -> { if (exchange.getRequestPath().equals("/")) { exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); exchange.getResponseSender().send("Hello World"); } }).build(); server.start(); } }
如果需要更复杂的路由,Undertow也支持类似Javalin的路由匹配规则,不用自己手动判断请求路径。
2. 直接用JDK自带的HttpServer
这个方案最省心,完全不需要额外引入任何第三方依赖,纯JDK原生实现,根本不会有Servlet版本冲突的问题。而且可以预先定义好处理器实例,不用为每个请求重复创建Handler。
示例代码:
import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; public class MyJdkHttpServer { public MyJdkHttpServer() throws IOException { HttpServer server = HttpServer.create(new InetSocketAddress(7000), 0); // 预先定义根路径的处理器,复用同一个实例 server.createContext("/", exchange -> { String response = "Hello World"; exchange.sendResponseHeaders(200, response.getBytes().length); try (OutputStream os = exchange.getResponseBody()) { os.write(response.getBytes()); } }); server.start(); } }
这个类是JDK1.6之后就自带的com.sun.net.httpserver.HttpServer,足够应付简单的HTTP服务场景,比如健康检查、轻量接口等。
3. 复用Spring生态的Embedded Tomcat
既然你本身是Spring MVC应用,也可以直接用Spring提供的嵌入式Tomcat,只要控制好依赖版本,确保不引入高版本的Servlet API就行。
示例代码:
import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.Tomcat; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class MyEmbeddedTomcatServer { public MyEmbeddedTomcatServer() throws LifecycleException { Tomcat tomcat = new Tomcat(); tomcat.setPort(7000); // 预先创建Servlet处理器实例,复用处理所有请求 HttpServlet helloServlet = new HttpServlet() { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType("text/plain"); PrintWriter out = resp.getWriter(); out.println("Hello World"); } }; tomcat.addServlet("", "helloServlet", helloServlet); tomcat.addServletMappingDecoded("/", "helloServlet"); tomcat.start(); } }
配置Maven/Gradle的时候,要确保tomcat-embed-core的版本和你现有Tomcat的版本兼容,同时排除掉任何带高版本Servlet API的依赖,避免隐性冲突。
最后提个小建议:不管用哪个方案,都要在构建工具里检查依赖树,确保javax.servlet-api:3.0是唯一的Servlet API依赖,从根源上避免版本冲突问题。
内容的提问来源于stack exchange,提问作者SnejOK

