原文: https://howtodoinjava.com/spring-mvc/contextloaderlistener-vs-dispatcherservlet/
在基于 XML 的 Spring MVC 配置中,您必须在web.xml
文件中看到两个声明,即ContextLoaderListener
和DispatcherServlet
。 让我们尝试了解它们在框架中的用途及其差异。
根和子上下文
在进一步阅读之前,请了解:
- Spring 一次可以有多个上下文。 其中之一将是根上下文,而所有其他上下文将是子上下文。
- 所有子上下文都可以访问在根上下文中定义的 Bean。 但事实并非如此。 根上下文无法访问子上下文 Bean。
DispatcherServlet
– 子应用程序上下文
DispatcherServlet
本质上是 Servlet(它扩展了HttpServlet
),其主要目的是处理与配置的 URL 模式匹配的传入 Web 请求。 它采用传入的 URI 并找到控制器和视图的正确组合。 因此它是前端控制器。
在 spring 配置中定义DispatcherServlet
时,您将使用contextConfigLocation
属性为 XML 文件提供控制器类,视图映射等条目。
web.xml
<servlet>
<servlet-name>employee-services</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:employee-services-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</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
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext.xml</param-value>
</context-param>
ContextLoaderListener
的上下文包含全局可见的 Bean,例如服务,存储库,基础结构 Bean 等。创建根应用程序上下文后,它作为属性存储在ServletContext
中,名称为:
org/springframework/web/context/ContextLoader.java
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
//Where attibute is defined in /org/springframework/web/context/WebApplicationContext.java as
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
要在 Spring 控制器中获取根应用程序上下文,可以使用WebApplicationContextUtils
类。
Controller.java
@Autowired
ServletContext context;
ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(context);
if(ac == null){
return "root application context is null";
}
ContextLoaderListener
与DispatcherServlet
下图在单个视图中描述了整个关系。
ContextLoaderListener
vs DispatcherServlet
ContextLoaderListener
创建根应用程序上下文。DispatcherServlet
条目为每个 Servlet 条目创建一个子应用程序上下文。- 子上下文可以访问在根上下文中定义的 bean。
- 根上下文中的 Bean 无法(直接)访问子上下文中的 Bean。
- 所有上下文都添加到
ServletContext
中。 - 您可以使用
WebApplicationContextUtils
类访问根上下文。
总结
通常,您将在DispatcherServlet
上下文中定义所有与 MVC 相关的 bean(控制器和视图等),并在ContextLoaderListener
的根上下文中定义所有跨领域的 bean,例如安全性,事务,服务等。
通常,此设置可以正常工作,因为很少需要访问任何 MVC bean(从子上下文)到与安全相关的类(从根上下文)。 通常,我们在 MVC 类上使用安全 bean,并且他们可以通过上述设置来访问它。
学习愉快!