Spring加载过程
Servlet3.0Spring 4.2.4-release1、容器的初始化:public interface ServletContainerInitializer {public void onStartup(Set<Class<?>
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);
更多推荐
所有评论(0)