1. 启动tomcat
2. 解析web.xml
如果配置了
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
这个类是spring提供了,它是一个servletLister,servlet的三大组件之一在tomcat启动的时候会调用
ContextLoaderListener extends ContextLoader implements ServletContextListener{
初始化方法
public void contextInitialized(ServletContextEvent event) {
创建Spring容器
this.initWebApplicationContext(event.getServletContext());{
this.context = this.createWebApplicationContext(servletContext);{
推断spring容器的类型
Class<?> contextClass = this.determineContextClass(sc);{
// 首先看有没有在web.xml中配置spring容器的类型
String contextClassName = servletContext.getInitParameter("contextClass");
if (contextClassName != null) {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}else{
// 如果没有,就使用默认的解析xml文件的web容器
// org.springframework.web.context.WebApplicationContext = org.springframework.web.context.support.XmlWebApplicationContext
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
}
// 刷新容器,解析spring.xml,创建bean对象
this.configureAndRefreshWebApplicationContext(cwac, servletContext);{
// 将servletContext放入Spring容器中
wac.setServletContext(sc);
// 获取配置的spring.xml文件路径
String configLocationParam = sc.getInitParameter("contextConfigLocation");
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
// 刷新容器
wac.refresh();
}
// 将创建的spring容器放入servletContext中
// 默认名称为org.springframework.web.context.WebApplicationContext.ROOT
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
}
}
}
}
3. 创建并初始化DispatcherServlet
3.1 调用DispatcherServlet.init(servlet生命周期方法) ->
DispatcherServlet extends FrameworkServlet extends HttpServletBean
extends HttpServlet extend GenericServlet implements Servlet,ServletConfig
javax.servlet.GenericServlet.init
public void init(ServletConfig config) throws ServletException {
this.config = config;
// 这个方法是给子类重写的,在springmvc的HttpServletBean重写了
this.init();
}
在HttpServlet并没有重写init方法
javax.servlet.http.HttpServlet extends GenericServlet
在HttpServletBean重写了
org.springframework.web.servlet.HttpServletBean extend HttpServlet{
重写父类的init方法
init(){
// 找web.xml中的配置信息
// 会将所有的init-params解析出来,通过名称进行反射执行set属性方法给对应的Servlet
// 如果需要设置DispatcherServlet,则可以在配置DispatcherServlet中添加init-param
// 因为DispatcherServlet是Tomcat创建的,所以我们没办法直接set
// 如果要给它设置的初始化属性那就属性只能存在ServletContext或者ServletConfig中
// 而web.xml正好提供了init-param来保存初始化属性,存在ServletConfig中,这样就达到了设置属性的效果
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);{
// 通过获取web.xml中配置的init-params
Enumeration<String> paramNames = config.getInitParameterNames();
while (paramNames.hasMoreElements()) {
// 将init-params的键值对获取出来,先保存起来
String property = paramNames.nextElement();
Object value = config.getInitParameter(property);
// 保持在一个集合中,后面使用
addPropertyValue(new PropertyValue(property, value));
}
}
// 如果配置了初始化属性
if (!pvs.isEmpty()) {
// 包装成BeanWrapper对象
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
// 将值设置为Servlet的属性,通过反射,配置的名称,比如contextConfigLocation,detectAllHandlerMappings
// 就是setDetectAllHandlerMappings,setContextConfigLocation,就将值复制给对应的Servlet
// 上面我们配置的是DispatcherServlet,所以这里设置的也是DispatcherServlet的属性
// 因为不同的Servlet有不同的init-param
bw.setPropertyValues(pvs, true);
}
// 初始化Servlet相关的Bean
initServletBean();{
// 创建SpringMVC容器
this.webApplicationContext = initWebApplicationContext();{
// 找已经创建的spring容器,看一下是否找的的,如果配置了ContextLoaderListener,就能找到,第二步有讲到
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());{
// 就是上面存入的spring容器
WebApplicationContext attr =(WebApplicationContext) sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}
WebApplicationContext wac = null;
if (wac == null) {
wac = createWebApplicationContext(rootContext);{
// 获取springmvc容器的类型,默认为public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
// 可以通过setContextClass修改容器的类型,默认是通过xml来创建容器
Class<?> contextClass = this.getContextClass();
// 创建springmvc容器
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
// 将rootContext(也就是spring容器)设置为springmvc的父容器
wac.setParent(parent);
// 获取配置的init-params的contextConfigLocation,在之前就已经保存了
// 通过反射设置的ContextConfigLocation,因为已经配置的ContextConfigLocation的值
// 只需要在ContextConfigLocation中添加set,就可以返回执行setContextConfigLocation方法
String configLocation = this.getContextConfigLocation();
// 设置需要解析的springmvc配置文件
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
// 刷新springmvc容器
this.configureAndRefreshWebApplicationContext(wac);{
// 设置ServletContext和config到spring容器中
wac.setServletContext(this.getServletContext());
wac.setServletConfig(this.getServletConfig());
wac.setNamespace(this.getNamespace());
// 发布一个spring的事件,该监听器监听ContextRefreshedEvent
wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));{
class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);{
// 刷新web容器
this.onRefresh(event.getApplicationContext());{
// 这里才真正达到DispatcherServlet中,执行初始化操作
// 初始化九大组件
this.initStrategies(context);
}
}
}
}
}
// 其实创建的就是StandardServletEnvironment
ConfigurableEnvironment env = wac.getEnvironment();{
public AbstractEnvironment() {
this(new MutablePropertySources());
}
protected AbstractEnvironment(MutablePropertySources propertySources) {
this.propertySources = propertySources;
// 配置属性,添加默认的属性
this.customizePropertySources(propertySources);{
// 将servletConfigInitParams,servletContextInitParams放入环境中,当成属性
// 后面会将StubPropertySource改成对应的ServletContextPropertySource/ServletConfigPropertySource
// 这里只是占位
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
}
}
}
// 加载属性,将ServletContext和ServletConfig存入环境对象的PropertySources中
if (env instanceof ConfigurableWebEnvironment) {
// 将默认的属性修改为对应servlet或者config的属性,因为上面创建环境的时候,使用的两个属性占位
((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());{
WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);{
String name = "servletContextInitParams";
if (servletContext != null && sources.get(name) instanceof StubPropertySource) {
// 将上面的StubPropertySource替换为ServletContextPropertySource
sources.replace(name, new ServletContextPropertySource(name, servletContext));
}
name = "servletConfigInitParams";
if (servletConfig != null && sources.get(name) instanceof StubPropertySource) {
sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
}
}
}
// 创建springmvc容器,并且设置了一些基本属性之后,进行的扩展操作,默认是空实现
this.postProcessWebApplicationContext(wac);
this.applyInitializers(wac);{
// 主要获取配置的初始化器,是获取spring提供的,在容器刷新前进行一些初始化操作
String globalClassNames = this.getServletContext().getInitParameter("globalInitializerClasses");
// 按照",;切割
String[] lis = StringUtils.tokenizeToStringArray(globalClassNames, ",; \t\n");
String className;
for(i = 0; i < lis.length; ++i) {
className = lis[i];
this.contextInitializers.add(this.loadInitializer(className, wac));
}
for(i = 0; i < lis.length; ++i) {
// 执行初始化器
ApplicationContextInitializer<ConfigurableApplicationContext> initializer = (ApplicationContextInitializer)var7.next();
initializer.initialize(wac);
}
}
// 刷新容器
wac.refresh();
}
return wac;
}
}
if (this.publishContext) {
String attrName = getServletContextAttributeName();{
// public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";
return SERVLET_CONTEXT_PREFIX + this.getServletName();
}
// 将springmvc容器放入servletContext中
getServletContext().setAttribute(attrName, wac);
}
}
// 初始化一些FrameworkServlet()的东西,默认是空实现,是给子类实现的
initFrameworkServlet();
}
}
}
初始化DispatcherServlet并创建Spring容器
于 2024-01-21 00:33:59 首次发布
本文详细解释了在Tomcat启动时,如何通过web.xml配置ContextLoaderListener和DispatcherServlet,以及它们在初始化过程中与Spring容器交互的过程,包括Spring容器的创建、配置文件解析和属性设置等关键步骤。
1082

被折叠的 条评论
为什么被折叠?



