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中,供后续使用。

  • 相关阅读:
    Linux 学习 step by step (1)
    ubuntu server nginx 安装与配置
    ubuntu server samba服务器配置
    iOS app集成支付宝支付流程及后台php订单签名处理
    mac 连接windows 共享内容
    linux 文件查找,which,whereis,locate,find
    ubuntu server vsftpd 虚拟用户及目录
    ubuntu server 安装 mantis bug tracker 中文配置
    ubuntu server vsftpd 匿名用户上传下载及目录设置
    linux 用户管理,用户权限管理,用户组管理
  • 原文地址:https://www.cnblogs.com/lay2017/p/11805470.html
Copyright © 2011-2022 走看看