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的所有启动流程,可以等待请求进入了。
相关推荐
Vio7253 小时前
Ribbon负载均衡
spring cloud·ribbon·负载均衡
lifallen4 小时前
从Apache Doris 学习 HyperLogLog
java·大数据·数据仓库·算法·apache
fire-flyer4 小时前
maven-jlink-plugin入门
java·maven
Knight_AL4 小时前
Java 单元测试全攻略:JUnit 生命周期、覆盖率提升、自动化框架与 Mock 技术
java·junit·单元测试
cominglately4 小时前
记录一次生产环境数据库死锁的处理过程
java·死锁
用户0332126663674 小时前
在 Word 文档中插入图片的 Java 指南
java
深圳蔓延科技4 小时前
单点登录到底是什么?
java·后端
SimonKing4 小时前
除了 ${},Thymeleaf 的这些用法让你直呼内行
java·后端·程序员
科兴第一吴彦祖4 小时前
基于Spring Boot + Vue 3的乡村振兴综合服务平台
java·vue.js·人工智能·spring boot·推荐算法