DispatcherServlet initialization process of Spring MVC source code analysis

DispatcherServelt is essentially a servlet, which is loaded by the servlet container.

1. The Servlet interface provides the initialization method of Servlet: init(ServletConfig config).

2. GenericServlet implements the method init(ServletConfig config), which calls the specific initialization method: init().

3. HttpServletBean rewrites the method init(), and uses the modifier final to make the method non-overridable, which can be understood by the template method: the logical process of initialization is defined in this method, and the specific implementation is determined by the sub- class to complete.

@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);
        }
    }
    // Let subclasses do whatever initialization they like.
    // 由子类FrameworkServlet来完成
    initServletBean();
}

4.FrameworkServlet rewrites initServletBean(), and uses the modifier final to make the method non-overridable. It can also be understood by the template method here.
The logical process of initialization is defined in this method, and the specific implementation is determined by the subclass. class to complete.

@Override
protected final void initServletBean() throws ServletException {
    try {
        // 调用initWebApplicationContext()方法,完成初始化
        this.webApplicationContext = initWebApplicationContext();
        // 方法体为空,子类可以重写实现扩展
        initFrameworkServlet();
    }
}

5. The method body of the method onRefresh(ApplicationContext context) called in FrameworkServlet.initWebApplicationContext is also empty, which is implemented by the subclass DispatcherServlet.

6. DispatcherServlet rewrites the method onRefresh, which calls the specific initialization process initStrategies(ApplicationContext context)

/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

7. The core initialization process of DispatcherServlet is completed by the following methods.

protected void initStrategies(ApplicationContext context) {
    // Spring MVC扩展点,核心的配置文件,也就是默认核心组件在DispatcherServlet.properties中
    // 1. 文件上传解析类,配置文件中没有默认配置.
    // 要想实现文件上传的功能,需要我们在xml配置文件中配置名multipartResolver名为multipartResolver的bean
    // 下面一行被注释的代码告诉我们,没有配置则不具备此功能
    // this.multipartResolver = null;
    // 此解析类需要实现接口MultipartResolver
    // 可以配置此类org.springframework.web.multipart.support.StandardServletMultipartResolver,作为文件上传的解析类
    // 当然也可以在xml文件中配置定制化的实现MultipartResolver接口的文件上传解析类
    initMultipartResolver(context);
    // 2.国际化
    initLocaleResolver(context);
    // 3.主题解析
    initThemeResolver(context);
    // 4.请求到处理器的映射
    initHandlerMappings(context);
    // 5.根据Handler的类型定义不同的处理规则
    initHandlerAdapters(context);
    // 6.Handler异常处理
    initHandlerExceptionResolvers(context);
    // 7.view->jsp,默认DefaultRequestToViewNameTranslator(JSP视图)
    initRequestToViewNameTranslator(context);
    // 8.视图解析:View视图解析成页面,可以设置多个解析策略,默认:InternalResourceViewResolver(JSP)
    initViewResolvers(context);
    // 9.重定向属性存储集合管理器
    initFlashMapManager(context);
}

8. Only the file upload component is explained in the above code, and the specific functions of other components will be described in detail in the following blog posts. Let's analyze the loading project of the default component. In the initialization method of the corresponding component, if the corresponding bean component instance can be detected, it will be used directly; if it cannot be detected, the default component configured in the default configuration file will be created by reflection. .

When the DispatcherServlet class is loaded, the default configuration file is parsed in the static code block.

static {
    // Load default strategy implementations from properties file.
    // This is currently strictly internal and not meant to be customized
    // by application developers.
    try {
        // 加载默认的配置文件
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
        // 将默认配置解析到集合Properties中
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    }
    catch (IOException ex) {
        throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
    }
}

Load the configured default components via reflection.

@SuppressWarnings("unchecked")
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList<>(classNames.length);
        for (String className : classNames) {
            try {
                // 反射方式ClassForName(className)加载Class对象
                Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                // 创建具体的组件
                Object strategy = createDefaultStrategy(context, clazz);
                strategies.add((T) strategy);
            }
            catch (ClassNotFoundException ex) {
                throw new BeanInitializationException(
                            "Could not find DispatcherServlet's default strategy class [" + className +
                                    "] for interface [" + key + "]", ex);
            }
            catch (LinkageError err) {
                throw new BeanInitializationException(
                            "Error loading DispatcherServlet's default strategy class [" + className +
                                    "] for interface [" + key + "]: problem with class file or dependent class", err);
            }
        }
        return strategies;
    }
    else {
        return new LinkedList<>();
    }

The initialization method of DispatcherServlet provides us with many extension points, allowing us to flexibly customize the DispatcherServlet service (only need to implement its corresponding interface and configure it in xml), to deeply control and extend DispatcherServlet's processing of Request requests every step.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325683321&siteId=291194637