Servlet3.0
Spring 4.2.4-release

参考:
https://www.jianshu.com/p/38f48c535988

1、容器的初始化:

public interface ServletContainerInitializer {
   public void onStartup(Set<Class<?>> c, ServletContext ctx)
        throws ServletException; 
}

ServletContainerInitializer这个初始化器在web容器启动时就会运行做一些组件内的初始化工作。下图是Spring对ServletContainerInitializer的实现。
ServletContext是容器上下文,webAppInitializerClasses为此类的具体实现,都将执行onStartup方法。
在这里插入图片描述

tomcat容器的ServletContainerInitializer机制:主要交由Context容器和ContextConfig监听器共同实现
ContextConfig监听器负责在容器启动时读取每个web应用的WEB-INF/lib目录下jar包的META-INF/services/javax.servlet.ServletContainerInitializer,以及web根目录下的META-INF/services/javax.servlet.ServletContainerInitializer,通过反射完成这些ServletContainerInitializer的实例化,然后再设置到Context容器中。
Context容器启动时就会分别调用每个ServletContainerInitializer的onStartup方法,并将注解@HandlesTypes上的类作为参数传入
具体分析参考 https://www.jianshu.com/p/38f48c535988

2、web.xml配置

<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
	
<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

使用了servlet3.0,实现ServletContainerInitializer,以上的xml配置可移除

Spring 初始化

在这里插入图片描述
由ContextLoaderListener执行根应用的上下文初始化,ContextLoaderListener只有contextInitialized、contextDestroyed方法。继承于ContextLoader,首先看下静态代码块,在此类下面有个ContextLoader.properties文件,

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

再来看最右侧初始化方法,创建createWebApplicationContext容器

从容器中取参数contextClass的值(这里可以实现ServletContainerInitializer,在onStartup方法中重新设置自定义的contextClass),没有找到对应的值则使用默认的XmlWebApplicationContext

	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

	protected Class<?> determineContextClass(ServletContext servletContext) {
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}

在这里插入图片描述

refresh()方法

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//创建bean工程,没有则创建,若有则销毁重建;实现对BeanDefinition的装载
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//配置bean工厂的标准上下文特性,如类装载器
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				//可重写方法,在bean定义被装载后,提供一个修改容器beanFactory的入口
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//在bean未开始实例化时,对Definition定义的修改入口。如PropertyPlaceholderConfigurer
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				//注册BeanPostProcessors用于Bean创建过程的拦截
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//容器初始化完成,preInstantiateSingletons会完成单例对象的创建
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

xml Bean对象的解析装载

//初始化
ClassLoader.initWebApplicationContext(servletContext)

//创建WebApplicationContext容器
ConfigurableWebApplicationContext cwac = ClassLoader.createWebApplicationContext(servletContext)

ClassLoader.configureAndRefreshWebApplicationContext(cwac, servletContext);
wac.setConfigLocation(configLocationParam);
//refresh方法见上图
wac.refresh();

//创建BeanFactory
ConfigurableListableBeanFactory beanFactory = AbstractRefreshableApplicationContext.refreshBeanFactory()

//开始加载解析Bean
XmlWebApplicationContext.loadBeanDefinitions(new XmlBeanDefinitionReader(beanFactory))

//解析xml
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(wac.location);
Document doc = xmlBeanDefinitionReader.doLoadDocument((new InputSource(EncodedResource.getInputStream()), resource)

//解析Document
DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(doc, createReaderContext(resource))

BeanDefinitionParserDelegate delegate = createDelegate(createReaderContext(resource), doc.getDocumentElement(), this.delegate)
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

//注册Bean
DefaultListableBeanFactory.registerBeanDefinition(bdHolder.beanName, bdHolder.beanDefinition)
ConcurrentHashMap.put(beanName, beanDefinition);



Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐