我们有一个应用程序可以从第三方库中加载ServletContainerInitializer的实例。
一个实例是JerseyServletContainerInitializer,另一个是SpringServletContainerInitializer。来自泽西岛和斯普林斯的这些课程似乎接替了#34;我们的servlet上下文弄乱了我们的映射和过滤器等。
我们确实需要显式配置我们的servlet容器的web.xml,这种自动扫描让我们疯狂。通过简单地在pom.xml中引入依赖项,我们的运行时ServletContext配置(如Servlets / Filters / ContextListeners)会发生变异,因为servlet容器会在类路径中找到这些库。
有没有办法使用Servlet 3但是禁用它烦人的自动类路径扫描"功能"?
答案 0 :(得分:9)
来自https://wiki.apache.org/tomcat/HowTo/FasterStartUp
您可以在WEB-INF / web.xml中指定两个选项 文件:
- 设置metadata-complete =" true" < web-app>上的属性元件。
- 添加空< absolute-ordering />元件。
设置metadata-complete =" true"禁用扫描您的网络 应用程序及其库,用于使用注释的类 定义Web应用程序的组件(Servlet等)。该 metadata-complete选项不足以禁用所有注释 扫描。如果有一个带有@HandlesTypes注释的SCI,则为Tomcat 必须扫描您的应用程序以查找使用注释或的类 该注释中指定的接口。
< absolute-ordering> element指定哪些Web片段JAR (根据其WEB-INF / web-fragment.xml文件中的名称) 扫描SCI,片段和注释。一个空的 element配置不扫描任何内容。
在Tomcat 7中,绝对排序选项会影响发现 Web应用程序提供的SCI和容器提供的SCI (即$ CATALINA_HOME / lib中的库)。在Tomcat 8中的选项 仅影响Web应用程序,而容器提供 无论绝对排序如何,总会发现SCI。在这样的 例如,绝对排序选项本身并不妨碍扫描 注释,但要扫描的JAR列表将为空,并且 因此扫描将很快完成。中的课程 无论绝对排序如何,都始终扫描WEB-INF /类。
扫描Web应用程序资源和TLD扫描不是 受这些选择的影响。
答案 1 :(得分:1)
有关Servlet 3.1规范的绝对排序的规范声明,请参见第8.2.2节&#34; web.xml和web-fragment.xml的排序&#34;,第1.d部分:< / p>
元素可以包含零个或一个 元件。描述了该元素所需的操作 下面。如果元素不包含 元素,任何未在其中具体提及的网络片段 元素必须被忽略。不扫描排除的罐子 带注释的servlet,过滤器或监听器。但是,如果是servlet, 来自排除jar的过滤器或监听器列在web.xml或a中 如果不排除web-fragment.xml,那么它的注释将适用 否则由metadata-complete排除。
关键的一点是,使用空的绝对排序元素不仅会关闭servlet-container初始值设定项的扫描。扫描所有定义注释的组件(例如@WebServlet)将被关闭。如果您确实要关闭Web应用程序中JAR文件的所有注释处理,则建议使用空的绝对排序元素。
扫描可以更精细地调整:使用绝对排序元素,并包含要使用名称元素扫描的JAR的名称,并省略您希望跳过的JAR。 不要使用其他元素,因为这会将所有未明确列出的JAR放回到排序中,并为这些JAR重新开启扫描。
作为一般惯例,我们发现关闭所有注释处理是危险的,因为启用注释扫描的Web应用程序有一些必须扫描的类,这意味着完全关闭扫描打破网络应用程序。
答案 2 :(得分:1)
我发现这两个答案都没有奏效。
从类路径中实际过滤出第三方SCI的唯一方法是Context
container的containerSciFilter
属性(在context.xml
中),定义为
指定哪个容器提供SCI的正则表达式 应该过滤掉而不用于此上下文。匹配用途 java.util.regex.Matcher.find()所以正则表达式只有 匹配容器的完全限定类名的子字符串 提供SCI以便将其过滤掉。如果未指定,则不进行过滤 将适用。
在我的情况下,我想过滤掉org.eclipse.jetty.apache.jsp.JettyJasperInitializer
之类的内容,因此我使用<Context ... containerSciFilter="jetty" ...>
答案 3 :(得分:0)
JIK 这是我的情况:
我不得不添加另一个项目作为我项目的依赖项,但该项目包含自己的 WebInit(即 AbstractAnnotationConfigDispatcherServletInitializer
的子类),因此当我的战争部署时,调用了两个 WebApplicationInitializer
(我的和另一个).
为了避免这种情况,我有
${projectRoot}/src/main/webapp/WEB-INF/web.xml
的 <absolute-ordering />
${projectRoot}/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
文本文件(文件名应准确为“javax.servlet.ServletContainerInitializer”)my.custom.package.MyCustomeServletContainerInitializer
MyCustomeServletContainerInitializer
添加一个类 my.custom.package
在我的例子中它是一个像这样的 kotlin 类class MyCustomeServletContainerInitializer: ServletContainerInitializer {
override fun onStartup(webAppInitializerClasses: MutableSet<Class<*>>?, servletContext: ServletContext) = ServletInitializer().onStartup(servletContext)
}
其中 ServletInitializer
是我自己实现的 WebApplicationInitializer
或更确切地说是 SpringBootServletInitializer