Tomcat-无法加载我的META-INF\services\javax.servlet.ServletContainerInitializer文件?

10
我有一个Web项目,其中包含一个\META-INF\services\javax.servlet.ServletContainerInitializer文件,其内容指向实现ServletContainerInitializer接口的类的完全限定名称。我基本上按照这里给出的示例进行操作:http://nullhaus.com/2011/03/using-servlets-3-0-servletcontainerinitializer/ 我在实现ServletContainerInitializer接口的类中放置了调试行,但它从未到达那里。甚至没有默认构造函数...
我的应用程序文件夹结构如下:
\MyApp
      \META-INF\services\javax.servlet.ServletContainerInitializer
      \WEB-INF\classes\
                 ... [list of classes and packages go here]

有什么想法需要检查吗?

注1:我的Tomcat从包含我的应用程序的外部文件夹发布

注2:我从Eclipse启动了Tomcat-如果这有所不同!


不,我不是。我只是你在帖子中提到的博客的作者,所以我很好奇是否能帮助你 :-) - Piotr Nowicki
啊,谢谢。看起来很简单,而且应该是这样的,但无论我尝试什么,它都不会触发。就好像javax.servlet.ServletContainerInitializer文件根本不存在一样。我能够在JBoss上半工作,所以我知道我的war文件设置没有问题,但与Tomcat如何扫描服务文件夹有关。 - Ayyoudy
你用的 Tomcat 版本是什么?我会尝试搭建你正在使用的环境。 - Piotr Nowicki
第二个更重要的问题是,你是否尝试将整个项目打包成*.jar文件,并在Tomcat中部署它? - Piotr Nowicki
抱歉伙计,我的意思是 *.war 文件,而不是 *.jar :-) - Piotr Nowicki
显示剩余3条评论
4个回答

5
我认为你需要将你的初始化器类(以及相关服务的META-INF目录)打成一个独立的*.jar文件,并放置在WEB-INF/lib目录下。
这是一个JAR服务,所以我想它可能与在*.war文件中发现服务的问题有关。此外,即使你把META-INF目录放在WEB-INF/classes中,并在Tomcat的server.xml中设置unpackWAR=false也是没有帮助的。
希望对你有所帮助。

谢谢您的回答。这可以解释这种行为。然而,我发现奇怪的是JBoss似乎可以使用我的设置,并且即使您没有将服务包装在Jar文件中,它也可以在Services文件夹内发现服务...但Tomcat却不行!无论如何,感谢您的帮助。 - Ayyoudy
很高兴能帮助你。当你说JBoss找到了服务时,你把“services”目录放在应用程序的哪里?是放在WEB-INF/classes/META-INF内还是与WEB-INF处于同一层级的META-INF内? - Piotr Nowicki
我确认这个答案。类和META-INF/services/javax.servlet.ServletContainerInitializer定义文件都必须在WEB-INF/lib目录下的单独的.jar文件中。将META-INF/services放在WAR文件中的/META-INF/services或WEB-INF/classes/META-INF/services中都不起作用。 - user207421
1
此外,如果相关的JAR文件被放置在Tomcat自己的lib目录中,它可以看到所有上下文初始化。如果它被放置在Web应用程序的WEB-INF/lib目录中,它只能看到该Web应用程序的上下文初始化。 - user207421
Spring Framework 3.1 提供了一个很好的解决方案来打包jar文件。spring-web-VERSION.jar 包含一个 ServletContainerInitializer 实现,并包括 META-INF/services/javax.servlet.ServletContainerInitializer 文件,该文件指示容器加载 org.springframework.web.SpringServletContainerInitializer。然后,SpringServletContainerInitializer 将加载任何扩展 Spring 的 WebApplicationInitializer 接口的类。此外,WebApplicationInitializer#onStartupServletContainerInitializer#onStartup 更简单易实现。 - Blair Zajac

4

为了让Tomcat加载META-INF目录,它必须位于classes文件夹中。如果您使用的是Maven项目,则只需将META-INF目录放在src/main/resources目录中。在mvn打包时,它将被复制到classes目录中。无需单独的jar文件。如果需要jar文件,可以使用HandlesTypes注释。


同样的情况,在Windows上使用进程监视器(Process Monitor)可以清楚地显示例如Tomcat 7.0.90正在扫描WEB-INF/classes/META-INF/services/[...]。在WEB-INF的同一级别下的META-INF似乎根本没有被使用。 - Thorsten Schöning
我的前面的声明对于在Eclipse内部使用和独立于Eclipse外部使用的Tomcat都是正确的,我已经测试过了。 - Thorsten Schöning

4

首先要检查的是您是否实际上正在使用Servlet 3.0而不是早期版本。对于Tomcat,这意味着您必须使用Tomcat 7.0.22。

其次,请确保在解压缩的war文件中实际存在\META-INF\services\javax.servlet.ServletContainerInitializer文件。

第三,如果不确定,请直接配置和启动Tomcat(而不是从Eclipse启动)-我看到开发人员在使用Eclipse插件配置Tomcat时遇到了无尽的问题。


1
我想引用来自Tomcat用户邮件列表的Mark Thomas <markt@apache.org>的好解释:
服务文件由META-INF / services目录中的类加载器加载。 *.jar!/ META-INF / services和*.war / WEB-INF / classes / META-INF / services对类加载器可见 *.war!/ META-INF / services则不是。
Servlet专家组最近在Java 9和多版本JAR的背景下讨论了WAR与JAR。结论是(我在这里简述):WAR不是JAR的专门形式,虽然它们共享通用格式,但除非Servlet规范(Java EE规范)明确说明,否则JAR可用的功能不会自动适用于WAR。
容器可以自由添加特定于容器的扩展,但它们带有通常的(缺乏)互操作性警告。

http://mail-archives.apache.org/mod_mbox/tomcat-users/201808.mbox/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接