原文: https://howtodoinjava.com/spring-mvc/contextloaderlistener-vs-dispatcherservlet/

在基于 XML 的 Spring MVC 配置中,您必须在web.xml文件中看到两个声明,即ContextLoaderListenerDispatcherServlet。 让我们尝试了解它们在框架中的用途及其差异。

根和子上下文

在进一步阅读之前,请了解:

  • Spring 一次可以有多个上下文。 其中之一将是根上下文,而所有其他上下文将是子上下文。
  • 所有子上下文都可以访问在根上下文中定义的 Bean。 但事实并非如此。 根上下文无法访问子上下文 Bean。

DispatcherServlet – 子应用程序上下文

DispatcherServlet本质上是 Servlet(它扩展了HttpServlet),其主要目的是处理与配置的 URL 模式匹配的传入 Web 请求。 它采用传入的 URI 并找到控制器和视图的正确组合。 因此它是前端控制器。

在 spring 配置中定义DispatcherServlet时,您将使用contextConfigLocation属性为 XML 文件提供控制器类,视图映射等条目。

web.xml

  1. <servlet>
  2. <servlet-name>employee-services</servlet-name>
  3. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  4. <init-param>
  5. <param-name>contextConfigLocation</param-name>
  6. <param-value>classpath:employee-services-servlet.xml</param-value>
  7. </init-param>
  8. <load-on-startup>1</load-on-startup>
  9. </servlet>

如果不提供配置文件,则它将使用[servlet_name]-servlet.xml加载其自己的配置文件。 Web 应用程序可以定义任意数量的DispatcherServlet条目。 每个 servlet 将在其自己的名称空间中运行,并使用映射,处理器等加载其自己的应用程序上下文。

这意味着每个DispatcherServlet都可以访问 Web 应用程序上下文。 在指定之前,每个DispatcherServlet都会创建自己的内部 Web 应用程序上下文

从Spring 3.x开始,方法DispatcherServlet(WebApplicationContext webApplicationContext)使用给定的 Web 应用程序上下文创建一个新的DispatcherServlet。 只有通过ServletContext.addServlet(java.lang.String, java.lang.String)API支持,才可以在 Servlet 3.x 环境中使用。

ContextLoaderListener – 根应用程序上下文

ContextLoaderListener创建根应用程序上下文,并将与所有DispatcherServlet上下文创建的子上下文共享。 在web.xml中只能有一个条目。

web.xml

  1. <listener>
  2. <listener-class>
  3. org.springframework.web.context.ContextLoaderListener
  4. </listener-class>
  5. </listener>
  6. <context-param>
  7. <param-name>contextConfigLocation</param-name>
  8. <param-value>/WEB-INF/spring/applicationContext.xml</param-value>
  9. </context-param>

ContextLoaderListener的上下文包含全局可见的 Bean,例如服务,存储库,基础结构 Bean 等。创建根应用程序上下文后,它作为属性存储在ServletContext中,名称为:

org/springframework/web/context/ContextLoader.java

  1. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
  2. //Where attibute is defined in /org/springframework/web/context/WebApplicationContext.java as
  3. WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

要在 Spring 控制器中获取根应用程序上下文,可以使用WebApplicationContextUtils类。

Controller.java

  1. @Autowired
  2. ServletContext context;
  3. ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(context);
  4. if(ac == null){
  5. return "root application context is null";
  6. }

ContextLoaderListenerDispatcherServlet

下图在单个视图中描述了整个关系。

`ContextLoaderListener`与`DispatcherServlet` - 图1

ContextLoaderListener vs DispatcherServlet

  1. ContextLoaderListener创建根应用程序上下文。
  2. DispatcherServlet条目为每个 Servlet 条目创建一个子应用程序上下文。
  3. 子上下文可以访问在根上下文中定义的 bean。
  4. 根上下文中的 Bean 无法(直接)访问子上下文中的 Bean。
  5. 所有上下文都添加到ServletContext中。
  6. 您可以使用WebApplicationContextUtils类访问根上下文。

总结

通常,您将在DispatcherServlet上下文中定义所有与 MVC 相关的 bean(控制器和视图等),并在ContextLoaderListener的根上下文中定义所有跨领域的 bean,例如安全性,事务,服务等。

通常,此设置可以正常工作,因为很少需要访问任何 MVC bean(从子上下文)到与安全相关的类(从根上下文)。 通常,我们在 MVC 类上使用安全 bean,并且他们可以通过上述设置来访问它。

学习愉快!