使用带注释的配置 war 的嵌入式 Jetty
Embedded Jetty with exploded war, using annotated config
我正在学习 Java EE 7 Servlet 并尝试使用嵌入式 Jetty (v 9.3.7) 从 Java EE 7 教程部署 hello2
example成功。 hello2
由两个servlet 和一个图像文件组成。配置有注释,项目没有任何web.xml。
在嵌入式 Jetty 的 WebAppContext
部分之后 examples 我创建了这个主要的 class 来启动我的嵌入式服务器:
public class MyServer {
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
String webappPath = new File(MyServer.class.getProtectionDomain().getCodeSource().getLocation().getFile())
.getParentFile().getParentFile().getAbsolutePath();
WebAppContext webapp = new WebAppContext(webappPath, "");
webapp.setConfigurations(new Configuration[]{
new AnnotationConfiguration()});
server.setHandler(webapp);
server.start();
server.join();
}
}
据我了解,由于 Jetty 是一个 Java EE Web 容器,它应该能够按原样提供示例 Serlvet 项目,我只需要指向 war 文件夹结构体。以下是项目结构:
-- hello2
\-- src
\-- main
+-- java
│ +-- MyServer.java
│ \-- javaeetutorial
│ \-- hello2
│ +-- GreetingServlet.java
│ \-- ResponseServlet.java
\-- webapp
+-- WEB-INF
│ \-- classes
│ +-- MyServer.class
│ \-- javaeetutorial
│ \-- hello2
│ +-- GreetingServlet.class
│ \-- ResponseServlet.class
+-- index.html
\-- resources
\-- images
\-- duke.waving.gif
可以找到 hello2
示例代码 here。以下是 GreetingServlet
的部分内容
@WebServlet("/greeting")
public class GreetingServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
....
和ResponseServlet
@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
....
文件被编译为 hello2/webapp/classes/
,从而使 webapp
文件夹成为展开的 WAR。 index.html 是我添加的,只是为了测试 Jetty 是否接收到它。结果是当我访问 localhost:8080、localhost:8080/greeting 或 localhost:8080/response
时出现错误 404
如果我添加 WebXmlConfiguration
和 webapp.setConfigurations()
,然后将资源库设置为 webapp.setResourceBase(webappPath)
,我设法进入 Jetty 的静态文件服务器。这是因为 Jetty 然后使用默认值 web.xml
将其自己的 servlet 添加到服务器以用于文件服务目的。但即便如此,我的带注释的 servlet 也没有被拾取。
我让 Jetty 读取带注释的 servlet 配置的方法是使用 WebAppContext.getMetadata().setWebInfClassesDirs()
显式设置 WEB-INF
目录:
webapp.getMetaData().setWebInfClassesDirs(
Arrays.asList(Resource.newResource(
MyServer.class.getProtectionDomain().getCodeSource().getLocation())));
然后,servlet 会按预期响应,但这不会为我的 index.html
或图像文件提供服务。我还将资源库设置为无用。所以我想要的是 Jetty 在没有 web.xml
的情况下为我的 Web 应用程序提供服务,只需将它指向展开的 WAR 目录即可。显然我错过了一些东西。
使用...
webapp.setConfigurations(new Configuration[]{
new AnnotationConfiguration()});
将撤消所有现有的重要配置,只启用 AnnotationConfiguration
。
难怪它对您不起作用,使用该设置,加载 WEB-INF/web.xml
的配置丢失,使用 WEB-INF/lib
的配置丢失,等等
您必须适当地修改现有的配置列表,并且有很多示例可以向您展示这一点。
因为你没有指定你是否有使用 JNDI 的注解,或者存在于 web 片段中,或者来自 webapp 上下文之外(比如容器本身),你需要的确切配置很难指定。
请参阅 https://github.com/jetty-project/embedded-servlet-3.1 项目以了解执行此操作的完整项目。
context.setConfigurations(new Configuration[]
{
new AnnotationConfiguration(),
new WebInfConfiguration(),
new WebXmlConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new JettyWebXmlConfiguration()
});
这是最常见的常规设置,但可能会让您接触到您可能不想要的额外配置。
即使您不想要其他组件,您仍然需要将它们留给已发现的 Web 应用程序。否则你有一个 100% 手动的网络应用程序,你专门调用 .addServlet()
和 .addFilter()
等。
您可能应该改用此语法。
private void enableAnnotationScanning(Server server)
{
Configuration.ClassList classlist = Configuration.ClassList.setServerDefault(server);
classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
}
因为这将修改现有的配置列表以仅添加 AnnotationConfiguration
如果您想查看此格式的其他示例,请查看以下示例项目:
- https://github.com/jetty-project/embedded-jetty-live-war - setting up a WAR file that can either be run via the command line with its own internal Jetty,或者部署到容器中。这会根据需要使用
AnnotationConfiguration
。
- https://github.com/jetty-project/embedded-jetty-uber-jar - setting up a single jar file with all of Jetty + your webapp, this uses the
ServletContextHandler
and manual setup 就像上面提到的那样。
在与 Joakim Erdfelt 讨论后,我进一步研究了 Tomcat,我了解到 Jetty 可能不是测试不同类型 Java EE 网络功能的最佳容器。 Jetty 通过 Glasshfish 和 Tomcat 以外的其他方式实现对 Java EE 的支持,这反过来又需要不同的设置方法,这在 Joakim 的回答下的讨论中进行了详细说明。
使用以下代码段
Tomcat 进行测试后
public class MyServer {
public static void main(String[] args) throws Exception {
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.addWebapp("","webapp");
tomcat.start();
tomcat.getServer().await();
}
}
起初看起来 Tomcat 不需要任何 web.xml,但在进一步调查之后,如果没有提供,Tomcat 使用默认值 web.xml。此 web.xml 包括一个 <welcome-file>index.html</welcome-file>
和一个提供静态内容的 DefaultServlet
。这种方法类似于 Jettys,我想这也是 Glassfish 的工作方式。所以吸取的教训是,总有某种 DefaultServlet 潜伏在 Java EE Web 服务器的后台,它完成了一些神奇的工作。即使 web.xml 对于服务器的用户来说是可选的,服务器仍然在后台提供它以使其自行工作。
我正在学习 Java EE 7 Servlet 并尝试使用嵌入式 Jetty (v 9.3.7) 从 Java EE 7 教程部署 hello2
example成功。 hello2
由两个servlet 和一个图像文件组成。配置有注释,项目没有任何web.xml。
在嵌入式 Jetty 的 WebAppContext
部分之后 examples 我创建了这个主要的 class 来启动我的嵌入式服务器:
public class MyServer {
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
String webappPath = new File(MyServer.class.getProtectionDomain().getCodeSource().getLocation().getFile())
.getParentFile().getParentFile().getAbsolutePath();
WebAppContext webapp = new WebAppContext(webappPath, "");
webapp.setConfigurations(new Configuration[]{
new AnnotationConfiguration()});
server.setHandler(webapp);
server.start();
server.join();
}
}
据我了解,由于 Jetty 是一个 Java EE Web 容器,它应该能够按原样提供示例 Serlvet 项目,我只需要指向 war 文件夹结构体。以下是项目结构:
-- hello2
\-- src
\-- main
+-- java
│ +-- MyServer.java
│ \-- javaeetutorial
│ \-- hello2
│ +-- GreetingServlet.java
│ \-- ResponseServlet.java
\-- webapp
+-- WEB-INF
│ \-- classes
│ +-- MyServer.class
│ \-- javaeetutorial
│ \-- hello2
│ +-- GreetingServlet.class
│ \-- ResponseServlet.class
+-- index.html
\-- resources
\-- images
\-- duke.waving.gif
可以找到 hello2
示例代码 here。以下是 GreetingServlet
@WebServlet("/greeting")
public class GreetingServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
....
和ResponseServlet
@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
....
文件被编译为 hello2/webapp/classes/
,从而使 webapp
文件夹成为展开的 WAR。 index.html 是我添加的,只是为了测试 Jetty 是否接收到它。结果是当我访问 localhost:8080、localhost:8080/greeting 或 localhost:8080/response
如果我添加 WebXmlConfiguration
和 webapp.setConfigurations()
,然后将资源库设置为 webapp.setResourceBase(webappPath)
,我设法进入 Jetty 的静态文件服务器。这是因为 Jetty 然后使用默认值 web.xml
将其自己的 servlet 添加到服务器以用于文件服务目的。但即便如此,我的带注释的 servlet 也没有被拾取。
我让 Jetty 读取带注释的 servlet 配置的方法是使用 WebAppContext.getMetadata().setWebInfClassesDirs()
显式设置 WEB-INF
目录:
webapp.getMetaData().setWebInfClassesDirs(
Arrays.asList(Resource.newResource(
MyServer.class.getProtectionDomain().getCodeSource().getLocation())));
然后,servlet 会按预期响应,但这不会为我的 index.html
或图像文件提供服务。我还将资源库设置为无用。所以我想要的是 Jetty 在没有 web.xml
的情况下为我的 Web 应用程序提供服务,只需将它指向展开的 WAR 目录即可。显然我错过了一些东西。
使用...
webapp.setConfigurations(new Configuration[]{
new AnnotationConfiguration()});
将撤消所有现有的重要配置,只启用 AnnotationConfiguration
。
难怪它对您不起作用,使用该设置,加载 WEB-INF/web.xml
的配置丢失,使用 WEB-INF/lib
的配置丢失,等等
您必须适当地修改现有的配置列表,并且有很多示例可以向您展示这一点。
因为你没有指定你是否有使用 JNDI 的注解,或者存在于 web 片段中,或者来自 webapp 上下文之外(比如容器本身),你需要的确切配置很难指定。
请参阅 https://github.com/jetty-project/embedded-servlet-3.1 项目以了解执行此操作的完整项目。
context.setConfigurations(new Configuration[]
{
new AnnotationConfiguration(),
new WebInfConfiguration(),
new WebXmlConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new JettyWebXmlConfiguration()
});
这是最常见的常规设置,但可能会让您接触到您可能不想要的额外配置。
即使您不想要其他组件,您仍然需要将它们留给已发现的 Web 应用程序。否则你有一个 100% 手动的网络应用程序,你专门调用 .addServlet()
和 .addFilter()
等。
您可能应该改用此语法。
private void enableAnnotationScanning(Server server)
{
Configuration.ClassList classlist = Configuration.ClassList.setServerDefault(server);
classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
}
因为这将修改现有的配置列表以仅添加 AnnotationConfiguration
如果您想查看此格式的其他示例,请查看以下示例项目:
- https://github.com/jetty-project/embedded-jetty-live-war - setting up a WAR file that can either be run via the command line with its own internal Jetty,或者部署到容器中。这会根据需要使用
AnnotationConfiguration
。 - https://github.com/jetty-project/embedded-jetty-uber-jar - setting up a single jar file with all of Jetty + your webapp, this uses the
ServletContextHandler
and manual setup 就像上面提到的那样。
在与 Joakim Erdfelt 讨论后,我进一步研究了 Tomcat,我了解到 Jetty 可能不是测试不同类型 Java EE 网络功能的最佳容器。 Jetty 通过 Glasshfish 和 Tomcat 以外的其他方式实现对 Java EE 的支持,这反过来又需要不同的设置方法,这在 Joakim 的回答下的讨论中进行了详细说明。
使用以下代码段
Tomcat 进行测试后public class MyServer {
public static void main(String[] args) throws Exception {
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.addWebapp("","webapp");
tomcat.start();
tomcat.getServer().await();
}
}
起初看起来 Tomcat 不需要任何 web.xml,但在进一步调查之后,如果没有提供,Tomcat 使用默认值 web.xml。此 web.xml 包括一个 <welcome-file>index.html</welcome-file>
和一个提供静态内容的 DefaultServlet
。这种方法类似于 Jettys,我想这也是 Glassfish 的工作方式。所以吸取的教训是,总有某种 DefaultServlet 潜伏在 Java EE Web 服务器的后台,它完成了一些神奇的工作。即使 web.xml 对于服务器的用户来说是可选的,服务器仍然在后台提供它以使其自行工作。