我应该如何从带有嵌入式码头的 web.xml 加载 servlet?
Posted
技术标签:
【中文标题】我应该如何从带有嵌入式码头的 web.xml 加载 servlet?【英文标题】:How should I load servlets from web.xml with embedded jetty? 【发布时间】:2020-02-02 22:44:00 【问题描述】:我正在尝试将我的应用程序从 tomcat 迁移到 embedded jetty。我按照一些指南(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
文件自动加载吗?
谢谢。
【问题讨论】:
【参考方案1】:您可以从 WEB-INF/web.xml
或注解加载 servlet。但是,如果您要嵌入,使用注释通常不是使用嵌入式服务器的最理想方式。
对于 Jetty,要使用 WEB-INF/web.xml
或使用 WebAppContext
的注释。这是一个重量级的组件,具有完整的 Servlet 规则和类加载器行为(re: 类加载器隔离)。
这对于嵌入式服务器来说通常是多余的,许多以这种方式开始的项目最终都会放弃它。
如果您依赖 Annotations,那么您将需要对您拥有的类进行字节码扫描,以一种所有进行字节码扫描的库都可以找到它们的方式公开它们。 Servlet 以自己的方式进行一次字节码扫描,而 JAXRS 层将以自己独特的方式再次进行一次。两者都非常希望通过ServletContext
接口及其关联的描述符信息找到他们的资源,这些信息指向哪里可以找到类。
Jetty 上更传统的设置是使用ServletContextHandler
。它本质上是 WebAppContext
的子集,没有类加载器隔离,允许您完全在代码中手动声明所有 Servlet 和过滤器及其映射。
这也使得启动非常快(适用于 docker 环境或微服务)。想想亚秒级启动。通过这种方式,只需很少的努力即可实现 100 毫秒的启动。
如果您必须坚持使用战争和 WebAppContext,请考虑对战争配置和资源进行构建时扫描,然后将 jetty-quickstart 元数据添加到您的战争中。那一小段 XML 加上快速启动运行时还可以让您在没有 web 应用发现步骤的情况下快速启动。
如果您想将嵌入式与 webapps 合并,并且可以选择在不重新打包的情况下使用传统意义上的应用程序,那么请考虑设置“实时战争”,这是可以通过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 服务器。【讨论】:
谢谢,@joakim-erdfelt!但是,由于其中定义了一些安全过滤器,我将保留web.xml
。
WEB-INF/web.xml
中的所有概念都可以在嵌入式码头使用中针对ServletContextHandler
用代码表示。包括您的 servlet 约束、安全过滤器、mime 类型等。
@JoakimErdfelt Hej!好吧,我们有一个现有的 web.xml 在独立的 tomcat 上运行良好,理想情况下,我们本来希望并且仍然希望能够使用嵌入式码头(或首先工作的 tomcat),但实际上是 1 - 1 映射。理想情况下,我们希望保留保留战争部署替代方案的选项,而不是像现在那样,必须为每个部署重写和使用特定于容器的代码。理想情况下,您应该能够为 Jetty 提供 web.xml,它应该从那里继续找出并设置所需的配置。不像现在,我必须手动配置它..
.. 使用难以正确处理的特定码头代码。我们还必须设置注释扫描并让 Web 套接字正常工作。 web.xml 有一个 listener 标记,在 jetty 中没有对应的标记。有了 tomcat,我们几乎一路走好,虽然它不是 1-1 独立的 tomcat。到目前为止,使用 Jetty,我们甚至无法掌握基础知识。如果我们真的启动并运行它,我们仍然希望保留原始的 web.xml 和 war 选项,尽管我可以看到这可能很难实现。
另外,我们的测试现在只输入 web.xml 并继续启动 Web 服务器。我不明白为什么码头也不能这样做。我不想学习和被孤立在码头。 web.xml 应该是通用的。以上是关于我应该如何从带有嵌入式码头的 web.xml 加载 servlet?的主要内容,如果未能解决你的问题,请参考以下文章
嵌入式 Jetty web 应用程序上下文/持有者从两个资源库和一个 web.xml (spring secuity) 提供服务
开始在java代码中嵌入码头,如何让它自动重新加载*.jsp/*.css/*.js?