IOC容器初始化之spring-servlet.xml容器(二)

序言

在一个web应用中,我们经常会配置两个Spring容器,一个是applicationContext.xml;另一个是spring-servlet.xml
applicationContext.xml的初始化是由ContextLoaderListener的initWebApplicationContext触发的。
而spring-servlet.xml的初始化时机是在applicationContext.xml初始化完成后,而MVC容器的初始化是在web容器loadServlet时触发GenericServlet的init(ServletConfig),再接着HttpServletBean中的init 中调用FrameworkServlet中的initServletBean。在该方法中,初始化servlet的子web容器,并将applicationContext创建的容器作为父容器。

Spring容器和Spring MVC容器的不同

  • 初始化时机不同,Spring容器优先初始化SpringMVC容器
  • Spring容器作为SpringMVC的父容器
  • Spring容器的触发是在创建完ServletContext时,触发ContextLoaderListener中的contextInitialized的initWebApplicationContext,而SpringMVC容器的触发是在loadServlet中初始化servletBean中创建子容器的
  • Spring子容器通常只管里controller层就可以,千万不要与父容器共管。【目前的项目共管的,因为之前搭建框架的人或者是后来在配置文件配置扫描bean包,导致使用我司的rsf,通过注解@Reference注入服务提供方代理对象,没生效。第一次被注入了【applicationContext容器初始化的时候】,在MVC子容器初始化的时候,该service又被创建了一次,新对象注入的为空,而在spring-servlet.xml中又没有消费方的注解声明,也就没有对应的BeanPostProcessor。】
  • 共管的话,会造成启动servlet子容器变慢。因为这一过程会有查找ControllerAdviceBean。这个查找过程是从该子容器下所有的beanName中查找。
	/**
	 * Instantiate the WebApplicationContext for this servlet, either a default
	 * {@link org.springframework.web.context.support.XmlWebApplicationContext}
	 * or a {@link #setContextClass custom context class}, if set.
	 * <p>This implementation expects custom contexts to implement the
	 * {@link org.springframework.web.context.ConfigurableWebApplicationContext}
	 * interface. Can be overridden in subclasses.
	 * <p>Do not forget to register this servlet instance as application listener on the
	 * created context (for triggering its {@link #onRefresh callback}, and to call
	 * {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
	 * before returning the context instance.
	 * @param parent the parent ApplicationContext to use, or {@code null} if none
	 * @return the WebApplicationContext for this servlet
	 * @see org.springframework.web.context.support.XmlWebApplicationContext
	 */
	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Servlet with name '" + getServletName() +
					"' will try to create custom WebApplicationContext context of class '" +
					contextClass.getName() + "'" + ", using parent context [" + parent + "]");
		}
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);
		wac.setConfigLocation(getContextConfigLocation());

		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());
			}
		}

		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);
		wac.refresh();
	}

Spring MVC 容器的初始化

初始化流程通过wac.refresh跟applicationContext一样。

Spring MVC子容器都做了哪些初始化工作?

  1. 创建工厂
  2. 加载Spring MVC的维持运转的核心BeanDefinition
    2.1 RequestMappingHandlerMapping的RootBeanDefinition注册
    2.2 ConfigurableWebBindingInitializer的RootBeanDefinition注册
    2.2.1 FormattingConversionServiceFactoryBean
    2.2.2 OptionalValidatorFactoryBean
    2.3 ManagedList,一些消息转换的ByteArrayHttpMessageConverter,
    StringHttpMessageConverter,ResourceHttpMessageConverter,
    SourceHttpMessageConverter,AllEncompassingFormHttpMessageConverter等。
    2.4 ManagedList,参数解析的
    2.5 ManagedList,返回值处理的
    2.6 RuntimeBeanReference,异步执行器
    2.7 ManagedList,回调拦截器
    2.8 ManagedList,延迟结果拦截器
    2.9 RequestMappingHandlerAdapter的RootBeanDefinition注册
    2.10 BeanNameUrlHandlerMapping注册
    2.11 HttpRequestHandlerAdapter注册
    2.12 SimpleControllerHandlerAdapter注册
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值