Jetty11不检测Servlet
我这里有一个示例项目,它使用 Jetty 部署本地服务器。
我使用该mvn package exec:java命令运行本地服务器,它工作正常。它加载 HTML 文件以及来自 servlet 的内容。以下是相关文件:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.happycoding</groupId>
<artifactId>app-engine-hello-world</artifactId>
<version>1</version>
<properties>
<!-- App Engine currently supports Java 11 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jetty.version>9.4.35.v20201120</jetty.version>
<!-- Project-specific properties -->
<exec.mainClass>io.happycoding.ServerMain</exec.mainClass>
<googleCloudProjectId>YOUR_PROJECT_ID_HERE</googleCloudProjectId>
</properties>
<dependencies>
<!-- Java Servlets API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- Jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>${jetty.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Copy static resources like html files into the output jar file. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-web-resources</id>
<phase>compile</phase>
<goals><goal>copy-resources</goal></goals>
<configuration>
<outputDirectory>
${project.build.directory}/classes/META-INF/resources
</outputDirectory>
<resources>
<resource><directory>./src/main/webapp</directory></resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- Package everything into a single executable jar file. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${exec.mainClass}</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<!-- App Engine plugin for deploying to the live site. -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>2.2.0</version>
<configuration>
<projectId>${googleCloudProjectId}</projectId>
<version>1</version>
</configuration>
</plugin>
</plugins>
</build>
</project>
服务器主程序
package io.happycoding;
import java.net.URL;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
/**
* Starts up the server, including a DefaultServlet that handles static files,
* and any servlet classes annotated with the @WebServlet annotation.
*/
public class ServerMain {
public static void main(String[] args) throws Exception {
// Create a server that listens on port 8080.
Server server = new Server(8080);
WebAppContext webAppContext = new WebAppContext();
server.setHandler(webAppContext);
// Load static content from inside the jar file.
URL webAppDir =
ServerMain.class.getClassLoader().getResource("META-INF/resources");
webAppContext.setResourceBase(webAppDir.toURI().toString());
// Enable annotations so the server sees classes annotated with @WebServlet.
webAppContext.setConfigurations(new Configuration[]{
new AnnotationConfiguration(),
new WebInfConfiguration(),
});
// Look for annotations in the classes directory (dev server) and in the
// jar file (live server)
webAppContext.setAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/target/classes/|.*.jar");
// Handle static resources, e.g. html files.
webAppContext.addServlet(DefaultServlet.class, "/");
// Start the server!
server.start();
System.out.println("Server started!");
// Keep the main thread alive while the server is running.
server.join();
}
}
HelloWorldServlet.java
package io.happycoding.servlets;
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/hello")
public class HelloWorldServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setContentType("text/html;");
response.getWriter().println("<h1>Hello world!</h1>");
}
}
同样,这很好用……只要我使用的是 Jetty 9。
但是,如果我更新我的pom.xml文件以将 my 设置jetty.version为11.0.0,那么我的 servlet URL 会突然出现 404。我在控制台中没有看到任何错误。
我需要对代码进行哪些更改才能让 servlet 在 Jetty 11 中再次工作?
(我之所以这么问,是因为我收到了大量对各种学生项目的依赖更新,这些项目都停止了工作,我正试图以尽可能少的摩擦来解决它们。)
回答
Jetty 11 基于 Jakarta Servlet 5.0,它是 Jakarta EE 9 的一部分。
Jakarta EE 9 经历了命名空间和包装的“大爆炸”更改(他们的名字,不是我的),现在不再javax.servlet.*是jakarta.servlet.*.
Jetty 11 中几乎没有任何东西可以查找javax.servlet.*.
一些快速的历史...
- Oracle 拥有 Java EE。
- Oracle 生产了 Java EE 7。
- Oracle 决定不再创建/管理 EE。
- Oracle 将所有 EE 交给了 Eclipse 基金会。
- Oracle 没有授予 Eclipse 基金会在这个新的 EE 现实中使用“java”或“javax”的权利。
- 出于法律原因,Eclipse 基金会将其重命名为“Jakarta EE”。
- Eclipse Foundation 发布了“Jakarta EE 8”,它本质上只是出于法律原因重命名的“Java EE 7”(尚未更改包名称空间)
- Eclipse基金会改名为所有包装从
javax.<spec>到jakarta.<spec>法律上的原因。 - Eclipse Foundation 发布了“Jakarta EE 9”,它本质上只是“Jakarta EE 8”,但命名空间发生了变化(这是上面提到的“大爆炸”)
(请注意,我略读了这些步骤之间发生的许多其他事情)
javax.servlet.*死了,万岁jakarta.servlet.*。
Jetty 维护以下版本(目前)
- Jetty 9.4.x - Servlet 3.1 / Java EE 7 (javax.servlet)
- Jetty 10.x - Servlet 4.0 / Jakarta EE 8 (javax.servlet)
- Jetty 11.x - Servlet 5.0 / Jakarta EE 9 (jakarta.servlet)
永远不会有一个向后兼容的功能,同时允许javax.servlet和jakarta.servlet共存在码头的释放。(我们已经尝试过这个,Servlet 规范的复杂性使得这对于 HttpSession、RequestDispatcher、动态 servlet/过滤器注册等来说是站不住脚的)
我们所能希望的最好的(并且有几个项目开始这样做,所有的 alpha 质量 ATM)是某种工具,可以自动更新您的 jar 和/或新包装的源,然后在雅加达上运行基于服务器。
- When I use `jakarta.servlet:jakarta.servlet-api:5.0.0` in my `pom.xml` file and change my servlet file to use the right imports, I'm still getting a 404. And I am indeed using App Engine to deploy my live site, so there might be further complications there. So it sounds like the right thing to do for now is to just go back to Jetty 9. Thank you both for the replies. I'm going to leave this open for a bit just in case anybody has a fix, but if not I'll accept this shortly. Thanks again!