参考网站:https://www.cnblogs.com/RunForLove/p/5688731.html
通过对spring源码的解读,跟踪spring容器的启动过程,掌握SpringMVC是如何工作的;掌握Spring源码的设计和增强阅读源码的技巧。为可持续性的使用spring框架高效集成开发,解决系统一些疑难杂症提供强有力的支撑。
一、需要掌握的理论业务点:
1、Web容器初始化过程
2、Spring MVC 在web.xml中的配置
3、理解ServletContextListener
4、掌握理解ContextLoadListener
5、DispatcherServlet初始化(HttpServletBean • FrameworkServlet • DispatcherServlet)
6、ContextLoadListener与DispatcherServlet的关系
7、DispatcherServlet的设计
8、DispatcherServlet工作原理
二、分析各个理论节点的知识
1、要想了解spring容器在web容器中启动的过程,首先我们需要知道web容器在tomcat中的生命周期,方可理解spring容器是如何在web容器中启动、运行、以及销毁、的生命周期
上图展示了web容器在启动过程中主要业务走向,其官方给出的解释是:
When a web application is deployed into a container, the following steps must be performed, in this order, before the web application begins processing client requests.
1、Instantiate an instance of each event listener identified by a element in the deployment descriptor.
2、For instantiated listener instances that implement ServletContextListener, call the contextInitialized() method.
3、Instantiate an instance of each filter identified by a element in the deployment descriptor and call each filter instance's init() method.
4、Instantiate an instance of each servlet identified by a element that includes a element in the order defined by the load-on-startup element values, and call each servlet instance's init() method.
翻译是:
当web应用程序部署到容器中时,必须按照以下顺序在web应用程序开始处理客户机请求之前执行以下步骤。
实例化由部署描述符中的元素标识的每个事件侦听器的实例。
对于实现ServletContextListener的实例化侦听器实例,调用contextInitialized()方法。
实例化由部署描述符中的元素标识的每个过滤器的实例,并调用每个过滤器实例的init()方法。
实例化由元素标识的每个servlet的实例,该元素按加载启动元素值定义的顺序包含元素,并调用每个servlet实例的init()方法。
大致的意思是,tomcat在启动web容器的时候会启动一个叫ServletContextListener的监听器,每当在web容器中有ServletContextListener这个接口被实例化的时候,web容器会通知ServletContextListener被实例的对象去执行其contextInitialized()的方法进行相应的业务处理,而spring框架在设计的过程中ContextLoadListener这个类实现了ServletContextListener这个接口,因此每当有ContextLoadListener这个类被实例化的时候,web容器会通知他执行contextInitialized()这个方法
2、spring MVC在web.xml在的配置
app
contextConfigLocation
classpath:spring-starter.xml
Spring监听器
org.springframework.web.context.ContextLoaderListener
在web.xm配置中由
ContextLoaderListener中的contextInitialized()进行了spring容器的启动配置并且刷新实例化整个SpringApplicationContext中的Bean。因此,如果我们的Bean配置出错的话,在容器启动的时候,会抛异常出来的。
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
//Spring 启动的句柄,spring容器开始启动的根目录
if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!");
} else {
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if(logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
//处理spring容器是否已经创建(只创建没有创建spring的各个bean)
if(this.context == null) {
this.context = this.createWebApplicationContext(servletContext);
}
if(this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
if(!cwac.isActive()) {
if(cwac.getParent() == null) {
ApplicationContext parent = this.loadParentContext(servletContext);
cwac.setParent(parent);
}
//Spring容器创建完成后,加载spring容器的各个组件
this.configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if(ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
} else if(ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if(logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if(logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
} catch (RuntimeException var8) {
logger.error("Context initialization failed", var8);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
throw var8;
} catch (Error var9) {
logger.error("Context initialization failed", var9);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9);
throw var9;
}
}
}
以上完成Spring容器的创建 ,并在代码中配置加载Spring容器启动的配置文件,以及调用Spring容器的加载入口
this.configureAndRefreshWebApplicationContext(cwac, servletContext);
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
String configLocationParam;
if(ObjectUtils.identityToString(wac).equals(wac.getId())) {
configLocationParam = sc.getInitParameter("contextId");
if(configLocationParam != null) {
wac.setId(configLocationParam);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
//设置Spring容器启动的起始配置文件
configLocationParam = sc.getInitParameter("contextConfigLocation");
if(configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
ConfigurableEnvironment env = wac.getEnvironment();
if(env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);
}
this.customizeContext(sc, wac);
//初始化spring的各个组件,以及spring容器中的各个bean
wac.refresh();
}
Spring容器加载bean的过程入口:wac.refresh();
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
String configLocationParam;
if(ObjectUtils.identityToString(wac).equals(wac.getId())) {
configLocationParam = sc.getInitParameter("contextId");
if(configLocationParam != null) {
wac.setId(configLocationParam);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
//设置Spring容器启动的起始配置文件
configLocationParam = sc.getInitParameter("contextConfigLocation");
if(configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
ConfigurableEnvironment env = wac.getEnvironment();
if(env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);
}
this.customizeContext(sc, wac);
//初始化spring的各个组件,以及spring容器中的各个bean
wac.refresh();
}
加spring容器中bean
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
List priorityOrderedPostProcessors = new ArrayList();
List internalPostProcessors = new ArrayList();
List orderedPostProcessorNames = new ArrayList();
List nonOrderedPostProcessorNames = new ArrayList();
String[] var8 = postProcessorNames;
int var9 = postProcessorNames.length;
String ppName;
BeanPostProcessor pp;
for(int var10 = 0; var10 < var9; ++var10) {
ppName = var8[var10];
if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if(pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
} else if(beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
nonOrderedPostProcessorNames.add(ppName);
}
}
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, (List)priorityOrderedPostProcessors);
List orderedPostProcessors = new ArrayList();
Iterator var14 = orderedPostProcessorNames.iterator();
while(var14.hasNext()) {
String ppName = (String)var14.next();
BeanPostProcessor pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if(pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, (List)orderedPostProcessors);
//存放spring容器中加载的各个bean
List nonOrderedPostProcessors = new ArrayList();
Iterator var17 = nonOrderedPostProcessorNames.iterator();
while(var17.hasNext()) {
ppName = (String)var17.next();
pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if(pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, (List)nonOrderedPostProcessors);
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, (List)internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
通过SerlvetContextListener这一特性还可以做其它的运用,如缓存数据在服务启动过程中的初始化
https://blog.csdn.net/qq_31854907/article/details/86304955