最近在新项目中接触到
Spring MVC,在学习过程中对 Spring IoC 的配置产生了一些疑问。通过同事的指点,和查阅资料,现在初步对其做一点总结归纳:
在 Spring Web 应用中,有两种不同 IoC 容器的实现方式:ApplicationContext 与 WebApplicationContext。
其中,对于每一个 Web 应用,都只有唯一一个对应的 ApplicationContext。ApplicationContext 是由 ContextLoader
Listener 来实现的,通过如下方式在
web.
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.</param-value></context-param>
由于 ContextLoaderListener 实现了 ServletContextListener
接口,所以 ContextLoaderListener 会在 Web 容器启动时,默认执行它实现的方法,通过调用 ContextLoader.initWebApplicationContext() 自动装配 applicationContext.
WebApplicationContext 继承自 ApplicationContext,可以看做是 ApplicationContext 的一个子集。Spring Web 应用中每个 DispatcherServlet 都对应一个独立的 WebApplicationContext。 当ContextLoaderListener 和 DispatcherServlet 一起使用时,ContextLoaderListener 会先创建一个根 ApplicationContext,然后 DispatcherServlet 创建的 WebApplicationContext 则会绑定到根 ApplicationContext 之下。
web.
<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>classpath:spring-mvc-servlet.</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet>
所以也就不难理解为什么在 ApplicationContext 中定义的 bean 可以在每个 WebApplicationContext 中使用。
通常为了将 Web 层模块与底层业务模块分离,提供更高细粒度的注入控制,在 WebApplicationContext 中只会定义 web 相关的模块,如 Controller, ViewResolver 或 handlers。(每个 DispatcherServlet 是相互独立的)
在上面我们提到,比较受推崇的做法是将不同的模块交由不同的 ApplicationContext 来管理。那么在 web.
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.</param-value></context-param><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>classpath:spring-mvc-servlet.</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet>
在 spring-mvc-servlet 中:
<context:component-scan base-package="com.zhao"> <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/></context:component-scan>
在 applicationContext.
<context:component-scan base-package="com.shunra.vcat"> <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/></context:component-scan>
但其实在实际使用中我们并不一定需要遵守这个条约。尤其是对于较小的项目,很多时候其实仅靠 DispatchServlet 就可以很好地管理我们的 IoC 容器。这种情况下我们仅需要在 web.
<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>classpath:spring-mvc-servlet.</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet>
在 spring-mvc-servlet 中:
<context:component-scan base-package="com.zhao"></context:component-scan>
这样项目的配置看起来会简洁的多,而且统一放置的配置文件也会方便我们管理。
当然,Spring Framework 为我们提供了两种 ApplicationContext 自有他的道理,在以下一些情况中,我们还是需要对不同的 context 分别进行配置:
- 应用中包含的多个 DispatcherServlet 需要共享某个业务操作时
- 应用中包含的非 Spring servlets 需要注入某个业务操作时
所以在实际应用中,还是需要灵活思考,选择最合适的配置方式。不能总是期望能找到 silver bullet : )
原标题:Spring IoC 学习 ——ApplicationContext 与 DispatcherServlet
关键词:Spring