【问题标题】:How to disable Servlet 3.0 scanning and auto loading of components如何禁用 Servlet 3.0 扫描和自动加载组件
【发布时间】:2016-08-25 02:18:12
【问题描述】:

我们有一个应用程序不断从我们的 3rd 方库加载 ServletContainerInitializer 实例。

一个实例是 JerseyServletContainerInitializer,另一个是 SpringServletContainerInitializer。这些来自 Jersey 和 Spring 的类似乎“接管”了我们的 servlet 上下文,扰乱了我们的映射和过滤器等。

我们确实需要显式配置 servlet 容器的 web.xml,而这种自动扫描让我们发疯。通过简单地在我们的 pom.xml 中引入一个依赖项,我们的运行时 ServletContext 配置(例如 Servlets/Filters/ContextListeners)会发生变化,因为 servlet 容器会在类路径中找到这些库。

有没有办法使用 Servlet 3 但禁用其烦人的自动类路径扫描“功能”?

【问题讨论】:

  • 你真的尝试过用谷歌搜索“servlet 3 disable classpath scanning”吗?设置<web-app metadata-complete="true">
  • @Andreas 此配置不会禁用自动扫描,它只会在 lib 文件夹中禁用它,但它仍会查看 /class 文件夹。
  • @VitorCruz 由于部署良好的生产应用程序在WEB-INF/classes 文件夹中没有任何文件,因此影响不大。
  • @Andreas 你是什么意思? /WEB-INF/classes 是你放置 web 应用程序的类的地方,为什么一个部署良好的人不会使用这个文件夹?
  • @VitorCruz 因为部署良好的 webapp 也会将自己的文件打包到 jar 文件中。

标签: java spring tomcat servlets servlet-3.0


【解决方案1】:

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
  • 在包my.custom.package中添加一个类MyCustomeServletContainerInitializer,在我的例子中它是一个像这样的kotlin类
class MyCustomeServletContainerInitializer: ServletContainerInitializer {
    override fun onStartup(webAppInitializerClasses: MutableSet<Class<*>>?, servletContext: ServletContext) = ServletInitializer().onStartup(servletContext)
}

ServletInitializer 是我自己实现的WebApplicationInitializer 或者更确切地说是SpringBootServletInitializer

【讨论】:

    【解决方案2】:

    我发现给定的答案都不起作用。

    从类路径中实际过滤掉 3rd-party SCI 的唯一方法是 Context container(在 context.xml 中)的 containerSciFilter 属性,该属性定义为

    指定哪个容器提供 SCI 的正则表达式 应该被过滤掉并且不用于这个上下文。配套用途 java.util.regex.Matcher.find() 所以正则表达式只需要 匹配容器的完全限定类名的子字符串 提供 SCI 以将其过滤掉。如果未指定,则不过滤 将被应用。

    就我而言,我想过滤掉 org.eclipse.jetty.apache.jsp.JettyJasperInitializer 这样的东西,所以我使用了 <Context ... containerSciFilter="jetty" ...>

    【讨论】:

      【解决方案3】:

      根据 Servlet 3.1 规范,关于绝对排序的规范声明可在第 8.2.2 节“web.xml 和 web-fragment.xml 的排序”第 1.d 部分中找到:

      元素可能包含零或一 元素。描述了此元素所需的操作 以下。如果元素不包含 元素,任何未在其中特别提及的网络片段 元素必须被忽略。不扫描排除的罐子 带注释的 servlet、过滤器或侦听器。但是,如果是 servlet, 排除的 jar 中的过滤器或侦听器列在 web.xml 或 非排除的 web-fragment.xml,那么它的注释将适用,除非 否则会被 metadata-complete 排除。

      一个关键的结论是,使用一个空的绝对排序元素不仅会关闭对 servlet-container 初始化程序的扫描。扫描所有组件定义注释,例如@WebServlet,被关闭。仅当您确实想要关闭 Web 应用程序中 JAR 文件的所有注释处理时,才建议使用空的绝对排序元素。

      扫描可以更精细地调整:使用绝对排序元素,并使用名称元素包含要扫描的 JAR 的名称,并省略您希望跳过的 JAR。 不要使用其他元素,因为这会将所有未明确列出的 JAR 重新排序,并将重新打开对这些 JAR 的扫描。

      作为一般做法,我们发现关闭所有注释处理是危险的,因为启用注释扫描的 Web 应用程序有一些必须扫描的类,这意味着完全关闭扫描会破坏网络应用程序。

      【讨论】:

        【解决方案4】:

        来自https://wiki.apache.org/tomcat/HowTo/FasterStartUp

        有两个选项可以在你的 WEB-INF/web.xml 中指定 文件:

        • 元素上设置 metadata-complete="true" 属性。
        • 添加一个空的 元素。

        设置 metadata-complete="true" 禁用扫描您的网络 使用注释的类的应用程序及其库 定义 Web 应用程序的组件(Servlet 等)。这 metadata-complete 选项不足以禁用所有注释 扫描。如果有带有@HandlesTypes 注解的SCI,Tomcat 必须扫描您的应用程序以查找使用注释的类或 该注释中指定的接口。

        元素指定哪些 Web 片段 JAR (根据其 WEB-INF/web-fragment.xml 文件中的名称)有 扫描 SCI、片段和注释。一个空 element 配置不被扫描。

        在 Tomcat 7 中,绝对排序选项会影响两者的发现 Web 应用程序提供的 SCI 和容器提供的 SCI (即通过 $CATALINA_HOME/lib 中的库)。在 Tomcat 8 中,该选项 仅影响 Web 应用程序,而容器提供 无论绝对排序如何,总是会发现 SCI。在这样的 case 单独的绝对排序选项不会阻止扫描 注释,但要扫描的 JAR 列表将为空,并且 因此扫描将很快完成。中的班级 WEB-INF/类总是被扫描,不管绝对顺序。

        扫描 Web 应用程序资源和 TLD 扫描不是 受这些选项的影响。

        【讨论】:

        • 如果我禁用扫描,我是否可以明确指定仍然运行我的 WebApplicationInitializer 类?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-22
        • 1970-01-01
        • 2016-12-24
        • 2017-02-09
        • 1970-01-01
        • 2016-10-21
        相关资源
        最近更新 更多