spring源码解析-web系列(一):启动
spring源码解析-web系列(二):处理请求的过程
spring源码解析-web系列(三):九大组件之HandlerMapping
spring源码解析-web系列(四):九大组件之HandlerAdapter
spring源码解析-web系列(五):解析请求参数
spring源码解析-web系列(六):九大组件之ViewResolver
spring源码解析-web系列(七):九大组件之HandlerExceptionResolver
转载请标明出处:
https://blog.csdn.net/bingospunky/article/details/97262392
本文出自马彬彬的博客
俯视spring web
我们在使用spring-mvc时,一般会:
1、在web.xml中配置一个***contextConfigLocation***参数,值为spring的xml配置文件(不包含controller)路径,然后再配置一个 ContextLoaderListener 类型的listener。
2、配置一个DispatcherServlet类型的servlet,给该servlet配置contextConfigLocation类型的参数,值为spring的xml配置文件(只包含controller)路径。
在监听器ContextLoaderListener加载的过程中,会根据contextConfigLocation对应的xml内容构造一个ApplicationContext,默认类型为XmlWebApplicationContext。这个ApplicationContext与j2ee的ServletContext绑定的,作为该项目的rootApplicationContext。
在DispatcherServlet加载过程中,会根据servlet里配置的xml文件构造一个WebApplicationContext,每个DispatcherServlet对应一个WebApplicationContext。
WebApplicationContext
一个DispatcherServlet对应一个WebApplicationContext,在org.springframework.web.servlet.FrameworkServlet.initServletBean方法中创建,且保证执行一次refresh方法,该WebApplicationContext的parent是上述的rootApplicationContext。
一般项目中定义一个DispatcherServlet,也就是一个WebApplicationContext。同时spring支持存在多个DispatcherServlet,使用不同的配置响应不同的servlet。
刷新过程
1.FrameworkServlet的createWebApplicationContext方法创建WebApplicationContext,创建完成后会调用FrameworkServlet.configureAndRefreshWebApplicationContext方法刷新配置。
2.在configureAndRefreshWebApplicationContext方法中,先添加一个事件监听,监听ContextRefreshedEvent。
3.调用刚才创建的WebApplicationContext的refresh方法,该方法代码如下:
代码1 (org.springframework.context.support.AbstractApplicationContext.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.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
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.
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();
}
}
}
代码1 先清空beanFactory,获取一个纯净的beanFactory,然后添加各种PostProcessor,然后调用finishBeanFactoryInitialization(beanFactory);方法初始化所有非懒惰bean。最后调用finishRefresh();发送ContextRefreshedEvent事件。
4.第2步添加的事件监听被回调,调用FrameworkServlet.this.onApplicationEvent(event);方法,先标记FrameworkServlet.refreshEventReceived为true,表示已经刷新的web相关信息,进而调用DispatcherServlet.onRefresh方法刷新web相关信息,比如:HandlerMapping、ViewResolver等。
代码2 (org.springframework.web.servlet.DispatcherServlet):
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
代码2初始化不同组件思路是相似的,都是先去BeanFactory里根据类型获取相关对象,然后把这些对象存储在DispatcherServlet对应的变量里。
5.如果FrameworkServlet.refreshEventReceived对象为false,刷新web相关信息,这里已经在事件监听里刷新过了,所以不会再刷新一次。
总结
如果俯视spring mvc的话,在一个web项目中,会有一个ApplicationContext作为rootApplicationContext和ServletContext相互关联。对于每个DispatcherServlet,都有一个ApplicationContext和它对应。
如果平时spring mvc的话,它和其他的spring模块(或者别的框架)有着相同的模式,在启动时通过各种配置文件把需要的组件初始化到合适的位置;当使用时,在适当的位置直接获取它们。就像是Mybatis把相关组件都存在Configuration类里一样。区别就是spring-mvc框架中使用的组件较多、处理逻辑较复杂。