在使用spring+springMVC的web工程中,我们一般会在web.xml中做如下配置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.xml</param-value> </context-param> <!-- spring context listener --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- spring mvc dispatcher servlet --> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
这样就会产生两个spring容器,一个父容器,一个子容器。
父容器Root WebApplicationContext由ContextLoaderListener加载
子容器WebApplicationContext for namespace 'spring-servlet'由DispatcherServlet加载('spring-servlet'子容器的contextConfigLocation,web.xml中配置的)
从容器里面getBean的时候,先从本容器取,如果取不到再从父容器取
原码跟踪得到如下结果:
ContextLoaderListener:
beanFactory : org.springframework.beans.factory.support.DefaultListableBeanFactory@501af69e: defining beans [commonService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,propertyConfigurer,messageSource,exceptionHandler,compositeFilter,dataSource,sqlSessionFactory,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.mybatis.spring.mapper.MapperScannerConfigurer#0,tokenClient,formTokenManager,formTokenAspect,formTokenPointCut,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,responseAspect,responsePointCut,org.springframework.aop.aspectj.AspectJPointcutAdvisor#1,multiViewResolver,excelView]; root of factory hierarchy
applicationContext:(对象地址:6be04fe1,父容器:null)
(org.springframework.web.context.support.XmlWebApplicationContext@6be04fe1) Root WebApplicationContext: startup date [Thu Feb 16 09:42:54 CST 2017]; root of context hierarchy
contextId : org.springframework.web.context.WebApplicationContext:
beanFactory.registerResolvableDependency(ApplicationContext.class, this);将父容器(根容器)注册到父容器的beanFactory中
DispatcherServlet:
ServletContext : org.apache.catalina.core.ApplicationContextFacade@78d9af50
applicationContext : ( 对象地址:8323ee8,父容器:ContextLoaderListener加载的 applicationContext,即 Root WebApplicationContext)
(org.springframework.web.context.support.XmlWebApplicationContext@8323ee8) WebApplicationContext for namespace 'spring-servlet': startup date [Thu Jan 01 08:00:00 CST 1970]; parent: Root WebApplicationContext
contextId : org.springframework.web.context.WebApplicationContext:/spring
beanFactory.registerResolvableDependency(ApplicationContext.class, this); 将子容器注册到子容器的beanFactory中
父容器的ListableBeanFactory中注册的bean:(由ContextLoadListener初始化的容器)
(java.lang.String[]) [commonService initService pageService org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor propertyConfigurer messageSource exceptionHandler compositeFilter dataSource sqlSessionFactory transactionManager org.springframework.aop.config.internalAutoProxyCreator org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0 org.springframework.transaction.interceptor.TransactionInterceptor#0 org.springframework.transaction.config.internalTransactionAdvisor org.mybatis.spring.mapper.MapperScannerConfigurer#0 tokenClient formTokenManager formTokenAspect formTokenPointCut org.springframework.aop.aspectj.AspectJPointcutAdvisor#0 responseAspect responsePointCut org.springframework.aop.aspectj.AspectJPointcutAdvisor#1 multiViewResolver excelView org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor ICommonDao IPageDao]
子容器的ListableBeanFactory中注册的bean:(由DispatcherServlet初始化的容器)
(java.lang.String[]) [baseTestController captchaController errorPageTestController excelExportController exceptionHandlerTestController paramProcessController tokenTestController validatorTestController org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.aop.config.internalAutoProxyCreator mvcContentNegotiationManager org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0 org.springframework.format.support.FormattingConversionServiceFactoryBean#0 org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean#0 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0 mvcUriComponentsContributor org.springframework.web.servlet.handler.MappedInterceptor#0 org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0 org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0 org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0 org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0 org.springframework.web.servlet.view.InternalResourceViewResolver#0]
补充:bean中如果依赖注入了ApplicationContext,那么这个bean中注入的容器为持有这个bean的容器
web工程,web.xml配置如上
application.xml加载除了Controller之外的bean
<!-- 加载@Component, @Service, @Repository --> <context:component-scan base-package="com.cn.kvn.usage"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
spring-servlet.xml加载Controller bean
<!-- 加载@Controller --> <context:component-scan base-package="com.cn.kvn.usage.controller" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
那么在Controller bean中注入ApplicationContext拿到的是子容器,而在Service bean中注入ApplicationContext拿到的是父容器
@Controller @RequestMapping("/base") public class BaseTestController { @Resource ApplicationContext applicationContext; ...... } @Service public class CommonService implements ICommonService{ @Resource ApplicationContext applicationContext; ....... }
断点跟踪,在Display窗口中打出的信息如下:
this
(org.springframework.web.context.support.XmlWebApplicationContext) Root WebApplicationContext: startup date [Thu Feb 16 13:50:53 CST 2017]; root of context hierarchy
org.springframework.util.ObjectUtils.getIdentityHexString(this)
(java.lang.String) 11667308 // 父容器的地址
this
(org.springframework.web.context.support.XmlWebApplicationContext) WebApplicationContext for namespace 'spring-servlet': startup date [Thu Feb 16 13:53:47 CST 2017]; parent: Root WebApplicationContext
org.springframework.util.ObjectUtils.getIdentityHexString(this)
(java.lang.String) 3be4f169 // 子容器的地址
applicationContext
(org.springframework.web.context.support.XmlWebApplicationContext) WebApplicationContext for namespace 'spring-servlet': startup date [Thu Feb 16 13:53:47 CST 2017]; parent: Root WebApplicationContext
org.springframework.util.ObjectUtils.getIdentityHexString(applicationContext)
(java.lang.String) 3be4f169 // Controller 中注入的ApplicationContext
applicationContext
(org.springframework.web.context.support.XmlWebApplicationContext) Root WebApplicationContext: startup date [Thu Feb 16 13:50:53 CST 2017]; root of context hierarchy
org.springframework.util.ObjectUtils.getIdentityHexString(applicationContext)
(java.lang.String) 11667308 // Service 中注入的ApplicationContext