Spring4.x 番外(1):Spring 上下文容器(WebApplicationContext)初始化

初始化实现方式

  1. Spring 运用于Web应用,其Ioc容器使用的类型为org.springframework.web.context.WebApplicationContext类 。
  2. 在Web应用中Spring的上下文容器可以称之为RootApplicationContext,而MVC的上下文容器称之为WebApplicationContext或者ServletApplicationContext。两者是父子容器的关系。具体Spring 容器见 Spring4.x 笔记(2):Spring 的Ioc容器
  3. Spring 框架提供了用于启动Web应用上下文容器的监听器:ContextLoaderListener,且容器的初始化需要ServletContext对象的支持。
  • 需要在 Web.xml 中配置web容器监听器ServletContextListener
  • 或Servlet3.x中在web容器初始化接口中手动编码创建监听器ServletContextListener对象

使用 Web.xml 配置启动

  1. Schema 配置文件实现
  • 定义监听器 ContextLoaderListener 对象
  • 指定上下文参数 contextConfigLocation 自定义配置文件地址。多个配置文件可以使用逗号、空格等分隔。不显式指定资源类型前缀,默认从Web的根路径获取
// 手动指定配置文件路径
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:/spring/spring-context.xml</param-value>
</context-param>

# 定义监听器
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  1. Web.xml 与Java Config 实现的配置类结合使用。使用注解 @Configuration 实现的Java类提供配置信息,web.xml 可以配置如下:
  • 配置 contextClass 参数,指定Spring 使用自定义的AnnotationConfigWebApplicationContext上下文容器类型替代默认的XmlWebApplicationContext类型
  • 配置初始化参数 contextConfigLocation 为Java Config 实现的配置类。一般为标注了@Configuration 的类。
# JavaConfig 配置,配置 contextClass 参数,指定Spring 使用  AnnotationConfigWebApplicationContext 上下文
<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
# 指定配置类:配置标注了@Configuration 的类
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>cn.com.sinosoft.smp.web.sys.config.SysConfig</param-value>
</context-param>

# 监听器,会根据上面配置使用 AnnotationConfigWebApplicationContext 根据 contextConfigLocation 指定的配置类启动容器
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

使用 SpringServletContainerInitializer 配置启动

  1. Servlet3.x 新增 ServletContext 的性能增强:( Servlet笔记系列(12):Servlet3.X版本新特性
  • 使用web容器初始化接口 ServletContainerInitializer 取代web.xml配置
  • 必须在 /META-INF/services/javax.servlet.ServletContainerInitializer 文件中配置实现类的全路径类名
  • 实现类需要使用@HandlesTypes注解来指定希望被处理的类,过滤掉不希望给 onStartup() 处理的类
  1. Spring 中SpringServletContainerInitializer实现了ServletContainerInitializer接口:
  • 在 spring-web 模块中有如下配置:/META-INF/services/javax.servlet.ServletContainerInitializer文件,内容为org.springframework.web.SpringServletContainerInitializer
  • 并且通过@HandlesTypes注解指定 WebApplicationInitializer 来处理具体的业务
  1. 在实现自定义配置时就可以实现 WebApplicationInitializer接口,重写 onStartup 方法,依次添加各种配置:
public class WebInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        # 注册上下文与配置,这边使用 Xml 实现或者 JavaConfig 实现都可以
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(MvcConfig.class);
        ctx.setServletContext(servletContext);

        // 手动创建 ContextLoaderListener 对象
        servletContext.addListener(new ContextLoaderListener(ctx));

        // 添加 CharacterEncodingFilter 拦截器
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("utf-8");
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", characterEncodingFilter);
        registration.setAsyncSupported(isAsyncSupported());
        registration.addMappingForUrlPatterns(getDispatcherTypes(), false, "/*");

        // 配置 spring mvc, 这边可以配置servlet的配置
        ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);

    }

    private boolean isAsyncSupported() {
        return true;
    }

    private EnumSet<DispatcherType> getDispatcherTypes() {
        return isAsyncSupported() ?
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) :
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
    }
}
  1. Spring 框架实现了一套WebApplicationInitializer接口的默认实现。
  • 核心模块有实现类AbstractContextLoaderInitializer
  • Mvc 模块有实现类 AbstractDispatcherServletInitializerAbstractAnnotationConfigDispatcherServletInitializer
  • 直接继承AbstractAnnotationConfigDispatcherServletInitializer类,覆盖默认的方法指定配置类,即可方便实现初始化的功能
  • getRootConfigClasses 指定 Spring 配置类
  • getServletConfigClasses 指定Spring Mvc 配置类
  • getServletMappings 指定Spring Mvc的 DispatcherServlet 的映射
public class WebInitializer2 extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{ApplicationConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
# Spring 配置类
@Configuration
@ComponentScan(basePackages = {"com.learning.spring.base.javaconfig"},
        excludeFilters = {@ComponentScan.Filter(classes = Controller.class)})
public class ApplicationConfig {
}
  1. AbstractAnnotationConfigDispatcherServletInitializer 实现类的类图如下

在这里插入图片描述

容器初始化

监听器对象的创建

  1. WebApplicationContext 上下文容器的初始化需要ContextLoaderListener监听器的支持,该监听器有两个构造函数,两种构造函数,正好对应着Web.xml配置和SpringServletContainerInitializer初始化类配置两种不同的实现方式。
构造函数类型对应初始化方式分析
无参构造Web.xml创建监听器对象,然后通过实现的ServletContextListener接口方法contextInitialized()创建和初始化容器WebApplicationContext
有参构造SpringServletContainerInitializer1、参数为WebApplicationContext对象,即先创建了容器对象WebApplicationContext
2、创建监听器对象,通过实现的ServletContextListener接口方法contextInitialized方法初始化容器WebApplicationContext
  1. SpringServletContainerInitializer 方式创建上下文容器对象在AbstractContextLoaderInitializer#registerContextLoaderListener方法中实现,该方法创建了WebApplicationContext对象,并且使用ContextLoaderListener类的有参构造函数,把创建的容器对象作为参数创建监听器实例
  • 值得注意的是在创建容器对象的方法中,首先会获取容器相关的配置类,然后再创建AnnotationConfigWebApplicationContext类型的容器对象
  • 获取容器相关的配置类的方法getRootConfigClasses,框架中没有实现,需要应用扩展使用。
	@Override
	protected WebApplicationContext createRootApplicationContext() {
	    # 获取配置类方法 getRootConfigClasses,需要应用自己扩展实现
		Class<?>[] configClasses = getRootConfigClasses();
		if (!ObjectUtils.isEmpty(configClasses)) {
			AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
			rootAppContext.register(configClasses);
			return rootAppContext;
		}
		else {
			return null;
		}
	}

监听器初始化

  1. ContextLoaderListener继承自ServletContextListener这个 ServletContext监听接口,覆盖了初始化方法contextInitialized(),该方法在应用启动时将被调用。在该方法主要的工作是完成容器 WebApplicationContext 的初始化
	@Override
	public void contextInitialized(ServletContextEvent event) {
	    # 调用初始化方法
		initWebApplicationContext(event.getServletContext());
	}
  1. WebApplicationContext创建初始化过程,简单总结为如下4个步骤:
  • 创建。判断上下文容器对象是否已经创建,如果没有则创建一个新的容器对象
  • 初始化。判断容器是否成功初始化(isActive状态),如未初始化,则执行容器的初始化工作
  • 设置容器关系。如果该容器有父容器,则还会设置其父容器。目前的设计来看,Spring 的容器为父容器,而Spring MVC 的容器为子容器。
  • 保存。初始化完成后,存入ServletContext对象中,以便后续在Web应用程序中使用。其中keyorg.springframework.web.context.WebApplicationContext.ROOT
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        ... ...

		try {
		    # 1- 创建上下文容器。先判断上下文容器对象是否已经创建
		    # Web.xml 配置实现,在这边创建上下文对象
		    # Servlet3.x方式实现中,已经提前了应用级别上下文对象,这边不需要创建
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				
				# 2- 初始化
				if (!cwac.isActive()) {
				    # 3-设置关系。 应用级别的容器本身就是父容器,不需要设置父容器
					if (cwac.getParent() == null) {
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					# 初始化。上下文配置与初始化。重点。
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			# 4-保存。设置到 servletContext。
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
            
            ... ...

			return this.context;
		}
            ... ...
	}
  1. 容器创建方法 createWebApplicationContext,只有在使用Web.xml 配置方式时才会被调用。先获取获取创建上下文容器的类型,然后利用反射直接创建。
	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
	    # 获取创建上下文容器的类型
		Class<?> contextClass = determineContextClass(sc);
        ... ...
        
		# 反射创建
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
  1. 在获取创建上下文容器的类型的方法中,需要注意的是框架默认创建的是XmlWebApplicationContext 类型,可以通过初始化参数 contextClass 自定义类型,如开篇手动指定的的AnnotationConfigWebApplicationContext类型
	protected Class<?> determineContextClass(ServletContext servletContext) {
	    
	    # 获取初始化参数 contextClass的值,看是否有指定的Ioc容器类的类型
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}   
		    ... ...
		}
		else {
		    # 没有指定,就使用配置文件(ContextLoader.properties)中默认配置的,为 XmlWebApplicationContext 类型
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			... ...
		}
	}
  1. 上下文容器配置与初始化方法configureAndRefreshWebApplicationContext()是整个过程的核心。所有初始化的工作部分都是在这边完成的,主要有:
编号任务名称具体事项
1设置容器的唯一Id1、可以使用初始化参数contextId自定义
2、默认值为一个组合值,为WebApplicationContext类的全路径名称加上ContextPath的值。如当ContextPath为空时,容器ID为org.springframework.web.context.WebApplicationContext:
2设置 ServletContext属性ServletContext 对象作为属性存入应用上下文容器。
3设置 contextConfigLocation 属性获取初始化参数contextConfigLocation,并且设置到容器对象的属性中
4初始化占位符属性源这个操作在容器初始化(刷新操作)始终会被执行。这边执行的原因在于确保servlet属性源在刷新操作之前的任何后处理或初始化中都处于适当的位置
5自定义容器设置1、在容器初始化刷新之前自定义创建的容器
2、该自定义扩展功能专门由一个接口ApplicationContextInitializer实现
3、通过初始化属性contextInitializerClassesglobalInitializerClasses,指定自定义的ApplicationContextInitializer接口实现类 器
4、通过这个功能可以在容器对象初始化之前,扩展容器的功能
6上下文初始化调用AbstractApplicationContext#refresh方法完成初始化。具体见 Spring4.x 笔记(6):Ioc 容器高级-内部工作机制
	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
	
	    # 设置容器ID
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			... ...
		}

        # 设置 `ServletContext`  属性
		wac.setServletContext(sc);
		
		# 设置 `contextConfigLocation` 属性
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}

		# 初始化占位符属性源 。
		# wac环境的 #initPropertySources 方法在上下文 refresh 的过程会总会被调用,这边提前处理一次。
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}
		
        # 自定义容器设置。
		customizeContext(sc, wac);
		
		# 上下文刷新,即初始化
		wac.refresh();
	}

监听器销毁

在监听器的销毁方法中执行上文容器对象的关闭工作(close)以及清空 ServletContext 中的上下文容器对象并且销毁ServletContext中所有类路径以org.springframework.开头的DisposableBean接口的的实现类。

参考

  1. Spring4.x 笔记(2):Spring 的Ioc容器
  2. SpringMVC4.x 番外(1):Spring MVC 上下文容器始化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
META-INF/MANIFEST.MF META-INF/license.txt org.springframework.remoting.caucho.BurlapClientInterceptor.class org.springframework.remoting.caucho.BurlapProxyFactoryBean.class org.springframework.remoting.caucho.BurlapServiceExporter.class org.springframework.remoting.caucho.Hessian1SkeletonInvoker.class org.springframework.remoting.caucho.Hessian2SkeletonInvoker.class org.springframework.remoting.caucho.HessianClientInterceptor.class org.springframework.remoting.caucho.HessianProxyFactoryBean.class org.springframework.remoting.caucho.HessianServiceExporter.class org.springframework.remoting.caucho.HessianSkeletonInvoker.class org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor.class org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.class org.springframework.remoting.httpinvoker.HttpInvokerClientConfiguration.class org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.class org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean.class org.springframework.remoting.httpinvoker.HttpInvokerRequestExecutor.class org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter.class org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor.class org.springframework.remoting.jaxrpc.JaxRpcPortClientInterceptor.class org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean.class org.springframework.remoting.jaxrpc.JaxRpcServicePostProcessor.class org.springframework.remoting.jaxrpc.JaxRpcSoapFaultException.class org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactory.class org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactoryBean.class org.springframework.remoting.jaxrpc.ServletEndpointSupport.class org.springframework.remoting.jaxrpc.support.AxisBeanMappingServicePostProcessor.class org.springframework.remoting.jaxws.JaxWsPortClientInterceptor.class org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean.class org.springframework.remoting.jaxws.JaxWsSoapFaultException.class org.springframework.remoting.jaxws.LocalJaxWsServiceFactory.class org.springframework.remoting.jaxws.LocalJaxWsServiceFactoryBean.class org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter.class org.springframework.web.HttpRequestHandler.class org.springframework.web.HttpRequestMethodNotSupportedException.class org.springframework.web.HttpSessionRequiredException.class org.springframework.web.bind.EscapedErrors.class org.springframework.web.bind.MissingServletRequestParameterException.class org.springframework.web.bind.RequestUtils.class org.springframework.web.bind.ServletRequestBindingException.class org.springframework.web.bind.ServletRequestDataBinder.class org.springframework.web.bind.ServletRequestParameterPropertyValues.class org.springframework.web.bind.ServletRequestUtils.class org.springframework.web.bind.WebDataBinder.class org.springframework.web.bind.annotation.InitBinder.class org.springframework.web.bind.annotation.ModelAttribute.class org.springframework.web.bind.annotation.RequestMapping.class org.springframework.web.bind.annotation.RequestMethod.class org.springframework.web.bind.annotation.RequestParam.class org.springframework.web.bind.annotation.SessionAttributes.class org.springframework.web.bind.support.ConfigurableWebBindingInitializer.class org.springframework.web.bind.support.DefaultSessionAttributeStore.class org.springframework.web.bind.support.SessionAttributeStore.class org.springframework.web.bind.support.SessionStatus.class org.springframework.web.bind.support.SimpleSessionStatus.class org.springframework.web.bind.support.WebBindingInitializer.class org.springframework.web.context.ConfigurableWebApplicationContext.class org.springframework.web.context.ContextLoader.class org.springframework.web.context.ContextLoaderListener.class org.springframework.web.context.ContextLoaderServlet.class org.springframework.web.context.ServletConfigAware.class org.springframework.web.context.ServletContextAware.class org.springframework.web.context.WebApplicationContext.class org.springframework.web.context.request.AbstractRequestAttributes.class org.springframework.web.context.request.AbstractRequestAttributesScope.class org.springframework.web.context.request.Log4jNestedDiagnosticContextInterceptor.class org.springframework.web.context.request.RequestAttributes.class org.springframework.web.context.request.RequestContextHolder.class org.springframework.web.context.request.RequestContextListener.class org.springframework.web.context.request.RequestScope.class org.springframework.web.context.request.ServletRequestAttributes.class org.springframework.web.context.request.ServletWebRequest.class org.springframework.web.context.request.SessionScope.class org.springframework.web.context.request.WebRequest.class org.springframework.web.context.request.WebRequestInterceptor.class org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.class org.springframework.web.context.support.ContextExposingHttpServletRequest.class org.springframework.web.context.support.GenericWebApplicationContext.class org.springframework.web.context.support.HttpRequestHandlerServlet.class org.springframework.web.context.support.PerformanceMonitorListener.class org.springframework.web.context.support.RequestHandledEvent.class org.springframework.web.context.support.ServletContextAttributeExporter.class org.springframework.web.context.support.ServletContextAttributeFactoryBean.class org.springframework.web.context.support.ServletContextAwareProcessor.class org.springframework.web.context.support.ServletContextFactoryBean.class org.springframework.web.context.support.ServletContextParameterFactoryBean.class org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer.class org.springframework.web.context.support.ServletContextResource.class org.springframework.web.context.support.ServletContextResourceLoader.class org.springframework.web.context.support.ServletContextResourcePatternResolver.class org.springframework.web.context.support.ServletRequestHandledEvent.class org.springframework.web.context.support.StaticWebApplicationContext.class org.springframework.web.context.support.WebApplicationContextUtils.class org.springframework.web.context.support.WebApplicationObjectSupport.class org.springframework.web.context.support.XmlWebApplicationContext.class org.springframework.web.filter.AbstractRequestLoggingFilter.class org.springframework.web.filter.CharacterEncodingFilter.class org.springframework.web.filter.CommonsRequestLoggingFilter.class org.springframework.web.filter.DelegatingFilterProxy.class org.springframework.web.filter.GenericFilterBean.class org.springframework.web.filter.Log4jNestedDiagnosticContextFilter.class org.springframework.web.filter.OncePerRequestFilter.class org.springframework.web.filter.RequestContextFilter.class org.springframework.web.filter.ServletContextRequestLoggingFilter.class org.springframework.web.jsf.DecoratingNavigationHandler.class org.springframework.web.jsf.DelegatingNavigationHandlerProxy.class org.springframework.web.jsf.DelegatingPhaseListenerMulticaster.class org.springframework.web.jsf.DelegatingVariableResolver.class org.springframework.web.jsf.FacesContextUtils.class org.springframework.web.jsf.SpringBeanVariableResolver.class org.springframework.web.jsf.WebApplicationContextVariableResolver.class org.springframework.web.jsf.el.SpringBeanFacesELResolver.class org.springframework.web.jsf.el.WebApplicationContextFacesELResolver.class org.springframework.web.multipart.MaxUploadSizeExceededException.class org.springframework.web.multipart.MultipartException.class org.springframework.web.multipart.MultipartFile.class org.springframework.web.multipart.MultipartHttpServletRequest.class org.springframework.web.multipart.MultipartResolver.class org.springframework.web.multipart.commons.CommonsFileUploadSupport.class org.springframework.web.multipart.commons.CommonsMultipartFile.class org.springframework.web.multipart.commons.CommonsMultipartResolver.class org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest.class org.springframework.web.multipart.support.ByteArrayMultipartFileEditor.class org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest.class org.springframework.web.multipart.support.MultipartFilter.class org.springframework.web.multipart.support.StringMultipartFileEditor.class org.springframework.web.util.CookieGenerator.class org.springframework.web.util.ExpressionEvaluationUtils.class org.springframework.web.util.HtmlCharacterEntityDecoder.class org.springframework.web.util.HtmlCharacterEntityReferences.class org.springframework.web.util.HtmlUtils.class org.springframework.web.util.HttpSessionMutexListener.class org.springframework.web.util.IntrospectorCleanupListener.class org.springframework.web.util.JavaScriptUtils.class org.springframework.web.util.Log4jConfigListener.class org.springframework.web.util.Log4jConfigServlet.class org.springframework.web.util.Log4jWebConfigurer.class org.springframework.web.util.NestedServletException.class org.springframework.web.util.TagUtils.class org.springframework.web.util.UrlPathHelper.class org.springframework.web.util.WebAppRootListener.class org.springframework.web.util.WebUtils.class org/springframework/web/context/ContextLoader.properties org/springframework/web/util/HtmlCharacterEntityReferences.properties

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值