【问题标题】:Embedded Jetty with exploded war, using annotated config带有爆炸战争的嵌入式码头,使用带注释的配置
【发布时间】:2016-09-27 15:29:18
【问题描述】:

我正在学习 Java EE 7 Servlet,并尝试使用嵌入式 Jetty (v 9.3.7) 从 Java EE 7 教程中部署 hello2 example,但收效甚微。 hello2 由两个 servlet 和一个图像文件组成。配置有注释,项目没有任何web.xml。

在嵌入式 Jetty examplesWebAppContext 部分之后,我创建了这个主类来启动我的嵌入式服务器:

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

如果我添加WebXmlConfigurationwebapp.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 目录即可。显然我错过了一些东西。

【问题讨论】:

    标签: java servlets embedded-jetty


    【解决方案1】:

    使用 ...

    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% 手动 web 应用程序,你专门调用 .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

    如果您想查看此格式的其他示例,请查看以下示例项目:

    【讨论】:

    • 正如我在问题中所写,我正在使用注释进行配置,而不是在 Java EE 7 中可选的 web.xml。另外,我相信我不需要 WEB-INF/lib,因为我是不使用它。我只使用了 AnnotationConfiguration,因为我从注解中配置了所有内容,并且我想了解它为什么不起作用。我的理论是这个设置应该适用于所有支持 servlet 容器的 Java EE 7。
    • 即使您没有实际文件,您仍然需要配置,因为这就是设置 webapp 元数据的方式。没有配置,没有元数据,没有关于设置的知识等。元数据是在所有这些配置上建立起来的。只有 Annotation/Plus/Env 是可选的,其余的都是必需的。
    • 添加 WebInfConfiguration 时,Jetty 开始读取我的注释配置 :) 我仍然认为我不应该需要 WebXmlConfiguration,因为我看到 Jetty 使用默认的 web.xml,它设置了一些内置的 servlet。但是没有它,Jetty 就不会为我的 index.html 提供服务。为什么 Jetty 必须添加自己的 web.xml 才能支持静态内容?我想我对 Jettys WebAppContext 感到困惑;它用于专门为 Web 应用程序提供服务(与 ServletContextHandler 相比),但不支持开箱即用的标准 Java EE 配置,无需使用 setConfigurations。
    • webdefault.xml 是标准 servlet 要求。 Jetty 不是 Java EE 顺便说一句,它只是一个支持 Servlet 的 Web 容器。
    • @qtips Jetty 对默认 Web 应用程序要求(如欢迎列表、默认 servlet、jsp 支持 url、TRACE 排除等)的解释是通过webdefault.xml 建立这些默认值,可以是在jetty-webapp-<ver>.jar 文件中作为资源找到,并在WebAppContext.setDefaultsDescriptor() 中被覆盖。 Jetty 是 Java EE 子集的子集,该标签需要 TCK 测试(与 OSS 不兼容)
    【解决方案2】:

    在与 Joakim Erdfelt 讨论后,我进一步研究了 Tomcat,我了解到 Jetty 可能不是测试不同类型 Java EE Web 功能的最佳容器。 Jetty 通过 Glasshfish 和 Tomcat 以外的其他方式实现对 Java EE 的支持,这反过来又需要不同的设置方法,这在 Joakims 答案下的讨论中进行了详细说明。

    使用 Tomcat 测试后使用以下 sn -p

    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 教程设置和期望它能够工作。您必须添加特定于码头的设置才能使其工作。当然这不是一个大问题,但是在学习 Java EE 和 sevlets 时可能会有点混乱。
    • 如果您专注于 Java EE,我建议您使用 TomEE,而不是普通的 Tomcat(因为它与 Jetty 处于相同的狭窄子集范围内)。但请注意,TomEE 并不擅长嵌入(主要是由于 Java EE 对其施加的限制)
    猜你喜欢
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 2015-12-06
    相关资源
    最近更新 更多