一、两个容器创建的时机
1.Spring容器
创建于ContextLoaderListener,当该监听器监听到项目启动时,便会创建applicationContext,并将此对象放入servletCongtext中。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml,classpath:spring-mybatis.xml</param-value>
</context-param>
<listener>
<description>spring监听器</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2.SpringMvc容器
该容器创建于DispatchServlet初始化时。
<servlet>
<description>spring rest</description>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
由于listener的执行顺序优先于servlet所以Spring容器先于SpringMvc容器存在,即Spring容器为父容器,SpringMvc容器为子容器。因父容器初始化时会将自己放入servletContext中,
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
子容器在初始化时就能得到父容器的存在,因而也就能使用父容器中的bean。
结语:使用spring容器的目的,我认为就是为了区分哪些bean是可以脱离web环境使用的。
问题一、为什么Controller注册在父容器中,注册在子容器中时,springMVC无法处理请求呢?
答:RequestMappingHandleMapping在找controller时,默认是不会从父容器中找的。所以我们可以手动的配置它从父容器找。但是这样针对特定的HandlerMapping配置不好。可以配置controller使用子容器装载。这样既分工明确,又可以免于配置。
注:采用父子容器制对事务的影响,子容器中即springMvc.xml中必须配置
<!-- 注解方式配置事物 -->
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" />
否则事务无法生效。原因待查。