SpringMVC启动流程

SpringMVC启动流程

文章目录

1.启动前的相关配置

  1. spring容器相关配置
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
							http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="com.anyi"></context:component-scan>
	<bean id="user" class="com.anyi.beans.User">
		<property name="username" value="anyi"></property>
		<property name="password" value="123"></property>
	</bean>
</beans>
  1. springmvc容器相关配置
java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>
  1. web.xml配置
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
		 version="4.0">
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-config.xml</param-value>
	</context-param>
	<servlet>
		<servlet-name>mvc-test</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:applicationContext.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>mvc-test</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>

2.启动流程

1.启动tomcat容器

使用idea会自动启动tomcat容器,调用spring容器的初始化方法

2.创建spring容器
  1. 在初始化tomcat容器之前,必须先启动tomcat容器,启动之后tomcat会调用初始化方法initWebApplicationContext()来对容器进行初始化
java 复制代码
@Override
public void contextInitialized(ServletContextEvent event) {
    // 初始化web容器,先开始初始化的spring容器
    initWebApplicationContext(event.getServletContext());
}
  1. 在这里会调用configureAndRefreshWebApplicationContext() 方法来进行spring容器的初始化
java 复制代码
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    // 设置一个容器id
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        // The application context id is still set to its original default value
        // -> assign a more useful id based on available information
        String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
        if (idParam != null) {
            wac.setId(idParam);
        }
        else {
            // Generate default id...
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                    ObjectUtils.getDisplayString(sc.getContextPath()));
        }
    }

    // 设置servlet上下文
    wac.setServletContext(sc);
    String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
    if (configLocationParam != null) {
        // 设置spring配置文件路径
        wac.setConfigLocation(configLocationParam);
    }

    // The wac environment's #initPropertySources will be called in any case when the context
    // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    // use in any post-processing or initialization that occurs below prior to #refresh
    // 设置一些环境对象
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
    }
    // 可以定制化context
    customizeContext(sc, wac);
    // 调用刷新方法
    wac.refresh();
}
  1. 刷新完成后,就完成了spring容器的初始化
3.创建springmvc容器

上述完成了tomcat、spring容器的创建和启动,接下来就是springmvc容器的启动了,而springmvc中最重要的就是Servlet,而Servlet的生命周期包含三个init、service、destroy。

  1. init方法调用是在DispatcherServlet的父类HttpServletBean中调用init()方法
java 复制代码
@Override
public final void init() throws ServletException {
    // 调用初始化springmvc容器
    // Set bean properties from init parameters.
    // 从web.xml中获取servlet的配置文件
    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
        try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        }
        catch (BeansException ex) {
            if (logger.isErrorEnabled()) {
                logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
            }
            throw ex;
        }
    }
	// 初始化ServletBean
    // Let subclasses do whatever initialization they like.
    initServletBean();
}
  1. 在initServletBean方法中会调用initWebApplicationContext()来进行springmvc容器的初始化
java 复制代码
protected WebApplicationContext initWebApplicationContext() {
    // 获取父容器
    WebApplicationContext rootContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    ...
    // 进行容器刷新
    configureAndRefreshWebApplicationContext(cwac);
    // 判断是否有事件发布
    if (!this.refreshEventReceived) {
        // Either the context is not a ConfigurableApplicationContext with refresh
        // support or the context injected at construction time had already been
        // refreshed -> trigger initial onRefresh manually here.
        synchronized (this.onRefreshMonitor) {
            onRefresh(wac);
        }
    }
    ...
    return wac;
}
  1. 调用configureAndRefreshWebApplicationContext()方法来刷新容器
java 复制代码
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    // id 验证
    ...
    // 设置一些属性值
    wac.setServletContext(getServletContext());
    wac.setServletConfig(getServletConfig());
    wac.setNamespace(getNamespace());
    // 放入一个ContextRefreshListener监听器
    wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

    // The wac environment's #initPropertySources will be called in any case when the context
    // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    // use in any post-processing or initialization that occurs below prior to #refresh
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
    }
    // 可以进行拓展修改
    postProcessWebApplicationContext(wac);
    // 设置一些初始化器
    applyInitializers(wac);
    // 开始容器刷新
    wac.refresh();
}
  1. 调用AbstractApplicationContext类中的refresh()方法来创建BeanFactory等容器刷新工作,详细见spring篇
  2. 在完成刷新后回到用一个方法finishRefresh()
java 复制代码
protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    // 清理缓存
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    // 实例化生命周期处理器
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    // 发布事件
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}
  1. 这里会调用publishEvent()方法,由多播器来广播发布一个容器已经完成刷新的事件,会调用具体的监听器来进行处理。
java 复制代码
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
	...
    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        // 调用多播器广播事件,让监听器来处理
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }
    ...
}
  1. 遍历所有的监听器,最终会由我们前面注册的一个ContextRefreshListener监听器来进行处理,最终会调用他的onApplicationEvent方法
java 复制代码
public void onApplicationEvent(ContextRefreshedEvent event) {
    this.refreshEventReceived = true;
    synchronized (this.onRefreshMonitor) {
        onRefresh(event.getApplicationContext());
    }
}
  1. 调用DispatcherServlet类中onRefresh(event.getApplicationContext())方法来完成springmvc九大模块的实例化
    1. 初始化 MultipartResolver:主要用来处理文件上传
    2. 初始化 LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver)
    3. 初始化 ThemeResolver:主要用来设置主题
    4. 初始化 HandlerMappings:映射器,用来完成request和controller的对应
    5. 初始化 HandlerAdapters:处理适配器,主要包含Http请求处理适配器,简单控制处理适配器,注解方法处理适配器
    6. 初始化 HandlerExceptionResolvers:基于HandlerExceptionResolver接口的异常处理
    7. 初始化RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或者逻辑视图名称,并且方法中没有直接往response的输入流中写入数据的时候
    8. 初始化 ViewResolvers:将ModelAndView选择合适的视图进行渲染处理器
    9. 初始化 FlashMapManager:提供请求存储属性,可供其他请求使用
java 复制代码
@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
protected void initStrategies(ApplicationContext context) {
    // 初始化 MultipartResolver:主要用来处理文件上传
    initMultipartResolver(context);
    // 初始化 LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver)
    initLocaleResolver(context);
    // 初始化 ThemeResolver:主要用来设置主题
    initThemeResolver(context);
    // 初始化 HandlerMappings:映射器,用来完成request和controller的对应
    initHandlerMappings(context);
    // 初始化 HandlerAdapters:处理适配器,主要包含Http请求处理适配器,简单控制处理适配器,注解方法处理适配器
    initHandlerAdapters(context);
    // 初始化 HandlerExceptionResolvers:基于HandlerExceptionResolver接口的异常处理
    initHandlerExceptionResolvers(context);
    // 初始化RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或者逻辑视图名称,并且方法中没有直接往response的输入流中写入数据的时候
    initRequestToViewNameTranslator(context);
    // 初始化 ViewResolvers:将ModelAndView选择合适的视图进行渲染处理器
    initViewResolvers(context);
    // 初始化 FlashMapManager:提供请求存储属性,可供其他请求使用
    initFlashMapManager:(context);
}
  1. 至此完成springmvc的所有启动流程,可以等待请求进入了。
相关推荐
7***37454 分钟前
Java设计模式之工厂
java·开发语言·设计模式
程序员小白条28 分钟前
你面试时吹过最大的牛是什么?
java·开发语言·数据库·阿里云·面试·职场和发展·毕设
大头an32 分钟前
JVM 内存结构深度解析(上篇):核心原理与运行时数据区
jvm
折翅嘀皇虫37 分钟前
fastdds.type_propagation 详解
java·服务器·前端
小年糕是糕手40 分钟前
【C++】类和对象(二) -- 构造函数、析构函数
java·c语言·开发语言·数据结构·c++·算法·leetcode
豐儀麟阁贵42 分钟前
8.2异常的抛出与捕捉
java·开发语言·python
老华带你飞44 分钟前
社区养老保障|智慧养老|基于springboot+小程序社区养老保障系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·小程序·毕设·社区养老保障
码龄3年 审核中44 分钟前
Linux record 03
java·linux·运维
q***87601 小时前
springboot下使用druid-spring-boot-starter
java·spring boot·后端
程序员西西1 小时前
SpringBoot无感刷新Token实战指南
java·开发语言·前端·后端·计算机·程序员