zoukankan      html  css  js  c++  java
  • 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组件的初始化方法

    组件初始化

    我们打开initMultipartResolver看看

    private void initMultipartResolver(ApplicationContext context) {
        try {
            this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
            // ...
        catch (NoSuchBeanDefinitionException ex) {
            // Default is no multipart resolver.
            this.multipartResolver = null;
            // ...
        }
    }

    其实就是从Bean工厂当中获取对应的Bean对象。multipartResolver默认可能为空

    再打开initViewResolvers看看

    private void initViewResolvers(ApplicationContext context) {
        this.viewResolvers = null;
    
        if (this.detectAllViewResolvers) {
            Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.viewResolvers = new ArrayList<>(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.viewResolvers);
            }
        } else {
            try {
                ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
                this.viewResolvers = Collections.singletonList(vr);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default ViewResolver later.
            }
        }
    
        if (this.viewResolvers == null) {
            this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
        }
    }

    一样的是从Bean工厂当中获取Bean,只不过这里是获取到一个集合,且如果没有将会获取默认的策略。

    其它的MVC组件初始化类似,这里不每个打开看了。

    总结

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

    初始化组件基本就是把各个Bean对象从BeanFactory中拿出来组合到DispatcherServlet中,供后续使用。

  • 相关阅读:
    ArcGIS Server 9.3 JavaScript API实战一个具体的小系统示例介绍
    感冒太难受了
    ACM考试的题目,收藏,有空做做
    用Java在Dos下,用纯字符画图
    考ACM需要的知识(转)
    换个风格,换种心情
    (C#)ACM考试题的第一题
    .net连Access的OleDb数据库连接字符串写法
    (C#)ACM考试题的第二题
    辗转相除
  • 原文地址:https://www.cnblogs.com/lay2017/p/11805470.html
Copyright © 2011-2022 走看看