springboot mvc源码解析(三)触发初始化mvc的组件

所有文章

https://www.cnblogs.com/lay2017/p/11775787.html

正文

springboot mvc自动配置的时候,获得了DispatcherServlet和DispatcherServletRegistrationBean。DispatcherServletRegistrationBean将DispatcherServlet给注册到了ServletContext当中。

注册到ServletContext中的Servlet将会触发其init方法,从而进行Servlet的初始化。本文将从Servlet的init方法开始,看看触发MVC各个组件初始化的代码

DispatcherServlet类图

我们先看看DispatcherServlet的类图

根据类图可以看到两部分的设计,第一部分是Servlet到HttpServlet,也就是Servlet容器相关的内部设计。第二部分是Spring在HttpServlet的基础上扩展了框架相关的内容,而最终DispatcherServlet将扩展springMVC的内容。

GenericServlet

我们跟进GenericServlet的init方法,看看它的实现

@Override
public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}

继续跟进init方法

public void init() throws ServletException {
    // NOOP by default
}

没有实现逻辑,供子类去选择实现

HttpServletBean

httpServlet么有实现init方法,由HttpServletBean这个spring实现的类来扩展。跟进HttpServletBean的init方法

@Override
public final void init() throws ServletException {

    // Set bean properties from init parameters.
    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;
        }
    }

    // Let subclasses do whatever initialization they like.
    initServletBean();
}

HttpServletBean也是扩展了一个initServletBean接口来供子类实现

FrameworkServlet

跟进FrameworkServlet的initServletBean的方法

@Override
protected final void initServletBean() throws ServletException {
    getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
    if (logger.isInfoEnabled()) {
        logger.info("Initializing Servlet '" + getServletName() + "'");
    }
    long startTime = System.currentTimeMillis();

    try {
        this.webApplicationContext = initWebApplicationContext();
        initFrameworkServlet();
    }
    catch (ServletException | RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        throw ex;
    }

    // ...
}

initFrameworkServlet是一个空实现,核心逻辑落到了initWebApplicationContext中,跟进它

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    if (this.webApplicationContext != null) {
        //...
    }
    if (wac == null) {
        wac = findWebApplicationContext();
    }
    if (wac == null) {
        wac = createWebApplicationContext(rootContext);
    }

    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            onRefresh(wac);
        }
    }

    if (this.publishContext) {
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}

Springboot在启动过程中创建了ApplicationContext,这里将公用同一个ApplicationContext。

onRefresh方法提供了一个空实现,供子类去做初始化实现

protected void onRefresh(ApplicationContext context) {
    // For subclasses: do nothing by default.
}

DispatcherServlet

跟进DispatcherServlet的onRefresh方法

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

继续跟进initStrategies

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

我们看到,initStrategies包含了各种MVC组件的初始化方法

总结

DispatcherServlet作为一个Servlet的实现,在Servlet被调用init方法以后最终将会调用DispatcherServlet的initStrategies方法,该方法将会初始化各个组件。

猜你喜欢

转载自www.cnblogs.com/lay2017/p/11805470.html