ContextLoaderListener与否?


122

一个标准的Spring Web应用程序(由Roo或“ Spring MVC Project”模板创建)使用ContextLoaderListener和创建一个web.xml DispatcherServlet为什么他们不仅使用DispatcherServlet并使其加载完整的配置?

我知道应该使用ContextLoaderListener来加载与Web不相关的内容,而DispatcherServlet用于加载与Web相关的内容(控制器等)。这样就产生了两个上下文:父上下文和子上下文。

背景:

我用这种标准方式做了几年了。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Handles Spring requests -->
<servlet>
    <servlet-name>roo</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/spring/webmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

这通常会导致两个上下文及其之间的依存关系出现问题。过去,我总是能够找到解决方案,并且我强烈感觉这使软件结构/体系结构总是更好。但是现在我面对两种情况的问题

-但是,这让我重新考虑了这两种上下文模式,我在问自己:我为什么要陷入这种麻烦,为什么不将所有spring配置文件都加载其中一个DispatcherServletContextLoaderListener完全删除。(我仍将拥有不同的配置文件,但只有一个上下文。)

有什么理由不删除ContextLoaderListener吗?


“这经常导致两个上下文及其之间的依赖关系出现问题。” 这是一个很好的例子,说明了我认为依赖注入框架比自己动手依赖注入会使我们的生活更加艰难。
安迪

1
@Andy-虽然我对此表示同情,但我不禁注意到您需要两个上下文的用例(在安全过滤器和Servlet之间共享对象,自动管理事务,以便在视图后将其关闭)如果没有框架的帮助,则很难重定向到您已经完成渲染的页面)。这主要是因为Servlet API显然根本没有设计成可以与依赖项注入一起使用,并且如果您自己尝试进行操作,则会对您不利。
Periata Breatta

@PeriataBreatta我明白了!好吧,您是否认为如果设计不同,Spring MVC会有更好的替代品吗?尽管人们本来可以设计出Servlet API的完整替代方案……
Andy

@PeriataBreatta有趣的是,在JS世界中,大约一年来我一直在使用Express来路由HTTP请求,我很少看到“依赖注入”的提法,而且根本没有类似Spring框架的提法。
安迪

Answers:


86

在您的情况下,没有,没有理由保留ContextLoaderListenerapplicationContext.xml。如果您的应用程序仅在servlet的上下文中运行良好,那么坚持下去,那就简单了。

是的,通常鼓励使用的模式是将非Web内容保留在webapp级别的上下文中,但这仅是一个较弱的约定。

使用webapp级上下文的唯一令人信服的理由是:

  • 如果您有多个DispatcherServlet需要共享服务
  • 如果您有旧版/非Spring servlet,需要访问Spring-wired服务
  • 如果你的servlet过滤器,勾入Web应用程序级范围内(如Spring Security的DelegatingFilterProxyOpenEntityManagerInViewFilter等等)

这些都不适合您,因此不需要额外的复杂性。

在将后台任务添加到servlet的上下文中时要特别小心,例如计划任务,JMS连接等。如果您忘记将其添加<load-on-startup>web.xml,那么直到首次访问Servlet时,这些任务才会启动。


2
关于侦听器,它表明它们需要由Context Loader侦听器创建Context(IllegalStateException,未找到WebApplicationContext,由MultipartFilter,CharacterEncodingFilter,HiddenHttpMethodFilter,Spring Security DelegatingFilterProxy和OpenEntityManagerInViewFilter触发)。是否以另一种方式来做是个好主意(通过ContextLoaderListener加载所有内容,并在不进行配置的情况下保留DispatcherServlet)?
拉夫

@Ralph:很好,我已经将用例添加到列表中。至于DispatcherServlet没有配置的情况-如果您这样做,则将没有Web界面。所有的MVC东西都必须放在那儿。
skaffman 2012年

2
@skaffman将Spring-security与DelegatingFilterProxy一起使用时,为什么要使用两个上下文?在我的情况下,spring-security bean和默认的spring上下文共享一些bean。因此,它们也应该共享相同的上下文。还是应该将Spring安全bean置于默认的Spring上下文之外?
Matthias M

10

您也可以用其他方式配置应用程序上下文。例如,为了使OpenEntityManagerInViewFilter工作。设置ContextLoaderListener,然后使用以下命令配置DispatcherServlet:

<servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value></param-value>
    </init-param>
</servlet>

只需确保contextConfigLocation参数值为空即可。


1
但是这种配置的优点是什么?您所说的“相反”是什么意思?
拉尔夫(Ralph)2013年

“ skaffman”的解决方案仅配置了Web应用程序上下文(servlet)。但是,使用这种方法会遇到解决方案本身中详述的问题:“使用webapp级上下文的唯一令人信服的原因是:” ...“如果您的servlet过滤器挂接到webbapp级上下文中(例如, Spring Security的DelegatingFilterProxy,OpenEntityManagerInViewFilter等)“如果您只想使用1个应用程序上下文XML文件,我认为我的解决方案(通过ContextLoaderListener指定XML)会更可取。
Gunnar Hillert 2013年

能够在由上下文侦听器创建的上下文中使用MVC Web控制器?
拉尔夫2013年

1
是。您只需在上下文侦听器指定的context.xml文件中设置控制器即可。它的工作方式是DispatcherServlet将简单地加入“父应用程序上下文”(Context Listener)。当您将“ contextConfigLocation”值保留为空时,将仅使用由上下文侦听器指定的context.xml文件。
Gunnar Hillert 2013年

1
我认为您在上下文中错过了<mvc:annotation-driven />。@GunnarHillert解决方案适用于我。
milbr 2014年

10

我想分享一下我在Spring-MVC应用程序中所做的工作:

  1. 在上,we-mvc-config.xml我只添加了@Controller注释的类:

    <context:component-scan base-package="com.shunra.vcat">
        <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>
  2. applicationContext.xml文件上,我添加了所有其余的文件:

    <context:component-scan base-package="com.shunra.vcat">
        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>

是的,这是一个有用的模式。另一个有用的模式是将数据库处理bean放在应用程序上下文中(OpenSessionInViewFilter或类似的对象可能需要这些)以及过滤器或侦听器特别需要的所有内容(例如,使用spring安全性所需的定义)。
Periata Breatta
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.