Tomcat 10报错javax.servlet.http.HttpServlet类未找到异常
实例化Servlet时触发500状态错误,查阅现有同类问题的解决方案均无法修复。
访问http://localhost:8080/SampServlet时返回错误:实例化Servlet类[com.example.SampServlet]失败,根因日志提示java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet。
相关代码与配置
SampServlet类代码
package com.example; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.io.PrintWriter; @WebServlet(name = "SampServlet", value = "/SampServlet") public class SampServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 向浏览器返回HTML内容 response.setContentType("text/html"); PrintWriter out = response.getWriter(); try { out.println("<h3>Testing Servlets</h3>"); } finally { out.close(); } } }
web.xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>SampServlet</servlet-name> <servlet-class>com.example.SampServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>SampServlet</servlet-name> <url-pattern>/SampServlet</url-pattern> </servlet-mapping> </web-app>
项目结构
完整错误日志
Message Error instantiating servlet class [com.example.SampServlet] Description The server encountered an unexpected condition that prevented it from fulfilling the request. Exception jakarta.servlet.ServletException: Error instantiating servlet class [com.example.SampServlet] org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356) org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1716) org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.base/java.lang.Thread.run(Thread.java:833) Root Cause java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet java.base/java.lang.ClassLoader.defineClass1(Native Method) java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1013) java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2527) org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:877) org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1413) org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1257) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356) org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1716) org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.base/java.lang.Thread.run(Thread.java:833) Root Cause java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1449) org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1257) java.base/java.lang.ClassLoader.defineClass1(Native Method) java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1013) java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2527) org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:877) org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1413) org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1257) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356) org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1716) org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.base/java.lang.Thread.run(Thread.java:833) Note The full stack trace of the root cause is available in the server logs.
核心问题是Servlet API包命名空间和当前使用的Tomcat版本不匹配:
错误栈开头就出现了jakarta.servlet.ServletException,说明运行环境是Tomcat 10及以上版本。从Tomcat 10开始,Java EE正式迁移为Jakarta EE,所有Servlet相关类的包名从javax.servlet.*全部改为jakarta.servlet.*,服务器内置的Servlet API只有jakarta开头的类。
代码中导入的全是javax.servlet.*包下的类,服务器加载SampServlet时找不到旧命名空间下的HttpServlet类,直接抛出类找不到异常,导致Servlet实例化失败。
另外代码已经通过@WebServlet注解配置了Servlet映射,web.xml中又重复配置了同路径的映射,虽然不是触发本次500错误的原因,但存在映射冲突隐患。
二选一即可修复:
- 方案1(适配当前Tomcat版本,推荐):将代码中所有
javax.servlet开头的导入语句全部替换为jakarta.servlet,修改后的导入部分如下:
import jakarta.servlet.*; import jakarta.servlet.http.*; import jakarta.servlet.annotation.*;
修改后可以将web.xml的命名空间和版本替换为Jakarta EE对应版本,也可以直接删掉web.xml中重复的Servlet配置,仅保留注解配置即可。
- 方案2(保留现有代码写法):将Tomcat降级到9.x及以下版本,Tomcat 9是最后一个使用
javax.servlet命名空间的版本,和现有代码、web.xml配置完全兼容。
注意:如果使用Maven/Gradle管理项目依赖,要将Servlet API依赖的scope设置为
provided,避免依赖包被打进项目部署包和Tomcat内置的Servlet包产生冲突。Tomcat 10及以上版本引入jakarta.servlet-api依赖,Tomcat 9及以下版本引入javax.servlet-api依赖,依赖版本和服务器版本对应即可。
内容的提问来源于stack exchange,提问作者user16482818

