我应该如何使用嵌入式码头从 web.xml 加载 servlet?
How should I load servlets from web.xml with embedded jetty?
我正在尝试将我的应用程序从 tomcat 迁移到 嵌入式码头 。我已经按照一些指南(this, this, this 等)在 web 模块中创建了一个入口点。生成的文件如下所示:
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext
object EPILauncher extends App {
val server: Server = new Server(8080)
val coolWebApplication = new WebAppContext()
coolWebApplication.setResourceBase("warehouse/src/main/webapp/")
coolWebApplication.setContextPath("/api")
coolWebApplication.setDescriptor("warehouse/src/main/webapp/WEB-INF/web.xml")
coolWebApplication.setParentLoaderPriority(true)
server.start()
System.out.println("Started!")
server.join()
}
我的 web.xml
文件中有以下 servlet 声明
<servlet>
<servlet-name>CustomerApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.xxxx.yyyy.warehouse.web.Root</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.jaxrs.listing,
org.owasp.csrfguard.servlet,
com.xxxx.yyyy.warehouse.resource
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.scanning.recursive</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>jersey.config.servlet.filter.staticContentRegex</param-name>
<param-value>.*(html|css|js|eot|svg|ttf|woff)</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>CustomerApplication</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
包 com.xxxx.yyyy.warehouse.resource
包含实现,例如:
@Singleton
@Path("/settings")
@Api("/settings")
class SettingsResource @Inject()(config: Config) {
@GET
@Path("/version")
@Produces(Array(MediaType.APPLICATION_JSON))
def getBackendVersion(@Context servletContext: ServletContext): Response = {
val manifestStream = servletContext.getResourceAsStream("META-INF/MANIFEST.MF")
val version: String = Option(manifestStream)
.map(Utils.using(_) { is =>
val attrs = new java.util.jar.Manifest(is).getMainAttributes
val version = attrs.getOrDefault(new Attributes.Name("Specification-Version"), "local-version").toString
val build = attrs.getOrDefault(new Attributes.Name("Implementation-Version"), "local-build").toString
s"$version.$build"
}).getOrElse("local-version.local-build")
Response.ok(VersionInfo(version)).build()
}
}
所以,当我 运行 我的应用程序并导航到 localhost:8080/api/settings/version
时,我看到的是:
URI: /api/settings/version
STATUS: 404
MESSAGE: Not Found
SERVLET: -
所以,我认为我没有正确理解一些概念。我是否应该在我的 main
方法中明确指出我想使用哪些 servlet?它们可以从 web.xml
文件自动加载吗?
谢谢。
您可以从 WEB-INF/web.xml
或注释中加载 servlet。但是如果你打算嵌入,使用注释通常不是使用嵌入式服务器的最理想方式。
对于 Jetty,要使用 WEB-INF/web.xml
或您使用 WebAppContext
的注释。这是一个重量级组件,具有完整的 Servlet 规则和类加载器行为(重新:类加载器隔离)。
这对于嵌入式服务器来说通常是矫枉过正,许多以这种方式开始的项目最终都会放弃它。
如果您依赖注释,那么您将需要对您拥有的 类 进行字节码扫描,以所有进行字节码扫描的库都可以找到它们的方式公开它们。 Servlet 以自己的方式扫描一次字节码,JAXRS 层将以自己独特的方式再次扫描。两者都非常希望通过 ServletContext
接口及其关联的描述符信息找到他们的资源,这些信息指向在哪里可以找到 类.
Jetty 上更传统的设置是使用 ServletContextHandler
。它本质上是 WebAppContext
的子集,没有类加载器隔离,并允许您完全在代码中手动声明所有 Servlet 和过滤器及其映射。
这也使得启动速度非常快(适用于 docker 环境或微服务)。想想亚秒级启动。以这种方式只需很少的努力就可以实现 100 毫秒的启动。
如果您必须坚持使用 war 和 WebAppContext,请考虑对 war 配置和资源进行构建时扫描,然后将 jetty-quickstart 元数据添加到您的 war .那一小块 XML,加上快速启动运行时,还可以让您快速启动,无需 webapp 发现步骤。
如果您想将嵌入式与 webapps 合并,并且可以选择在传统意义上使用该应用程序而无需重新打包,那么请考虑设置一个“实时 war”,这是一个 war可以通过 java -jar /path/to/myapp.war
.
直接执行
过去有关于使用 Live 的答案WAR ...
- How do I configure embedded jetty to used war file in executable jar as resource
- https://github.com/jetty-project/embedded-jetty-live-war - 显示实时可执行文件 war 的示例,该文件带有带注释扫描的内置 Jetty 服务器。
我正在尝试将我的应用程序从 tomcat 迁移到 嵌入式码头 。我已经按照一些指南(this, this, this 等)在 web 模块中创建了一个入口点。生成的文件如下所示:
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext
object EPILauncher extends App {
val server: Server = new Server(8080)
val coolWebApplication = new WebAppContext()
coolWebApplication.setResourceBase("warehouse/src/main/webapp/")
coolWebApplication.setContextPath("/api")
coolWebApplication.setDescriptor("warehouse/src/main/webapp/WEB-INF/web.xml")
coolWebApplication.setParentLoaderPriority(true)
server.start()
System.out.println("Started!")
server.join()
}
我的 web.xml
文件中有以下 servlet 声明
<servlet>
<servlet-name>CustomerApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.xxxx.yyyy.warehouse.web.Root</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.jaxrs.listing,
org.owasp.csrfguard.servlet,
com.xxxx.yyyy.warehouse.resource
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.scanning.recursive</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>jersey.config.servlet.filter.staticContentRegex</param-name>
<param-value>.*(html|css|js|eot|svg|ttf|woff)</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>CustomerApplication</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
包 com.xxxx.yyyy.warehouse.resource
包含实现,例如:
@Singleton
@Path("/settings")
@Api("/settings")
class SettingsResource @Inject()(config: Config) {
@GET
@Path("/version")
@Produces(Array(MediaType.APPLICATION_JSON))
def getBackendVersion(@Context servletContext: ServletContext): Response = {
val manifestStream = servletContext.getResourceAsStream("META-INF/MANIFEST.MF")
val version: String = Option(manifestStream)
.map(Utils.using(_) { is =>
val attrs = new java.util.jar.Manifest(is).getMainAttributes
val version = attrs.getOrDefault(new Attributes.Name("Specification-Version"), "local-version").toString
val build = attrs.getOrDefault(new Attributes.Name("Implementation-Version"), "local-build").toString
s"$version.$build"
}).getOrElse("local-version.local-build")
Response.ok(VersionInfo(version)).build()
}
}
所以,当我 运行 我的应用程序并导航到 localhost:8080/api/settings/version
时,我看到的是:
URI: /api/settings/version
STATUS: 404
MESSAGE: Not Found
SERVLET: -
所以,我认为我没有正确理解一些概念。我是否应该在我的 main
方法中明确指出我想使用哪些 servlet?它们可以从 web.xml
文件自动加载吗?
谢谢。
您可以从 WEB-INF/web.xml
或注释中加载 servlet。但是如果你打算嵌入,使用注释通常不是使用嵌入式服务器的最理想方式。
对于 Jetty,要使用 WEB-INF/web.xml
或您使用 WebAppContext
的注释。这是一个重量级组件,具有完整的 Servlet 规则和类加载器行为(重新:类加载器隔离)。
这对于嵌入式服务器来说通常是矫枉过正,许多以这种方式开始的项目最终都会放弃它。
如果您依赖注释,那么您将需要对您拥有的 类 进行字节码扫描,以所有进行字节码扫描的库都可以找到它们的方式公开它们。 Servlet 以自己的方式扫描一次字节码,JAXRS 层将以自己独特的方式再次扫描。两者都非常希望通过 ServletContext
接口及其关联的描述符信息找到他们的资源,这些信息指向在哪里可以找到 类.
Jetty 上更传统的设置是使用 ServletContextHandler
。它本质上是 WebAppContext
的子集,没有类加载器隔离,并允许您完全在代码中手动声明所有 Servlet 和过滤器及其映射。
这也使得启动速度非常快(适用于 docker 环境或微服务)。想想亚秒级启动。以这种方式只需很少的努力就可以实现 100 毫秒的启动。
如果您必须坚持使用 war 和 WebAppContext,请考虑对 war 配置和资源进行构建时扫描,然后将 jetty-quickstart 元数据添加到您的 war .那一小块 XML,加上快速启动运行时,还可以让您快速启动,无需 webapp 发现步骤。
如果您想将嵌入式与 webapps 合并,并且可以选择在传统意义上使用该应用程序而无需重新打包,那么请考虑设置一个“实时 war”,这是一个 war可以通过 java -jar /path/to/myapp.war
.
过去有关于使用 Live 的答案WAR ...
- How do I configure embedded jetty to used war file in executable jar as resource
- https://github.com/jetty-project/embedded-jetty-live-war - 显示实时可执行文件 war 的示例,该文件带有带注释扫描的内置 Jetty 服务器。