所有文章

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

springboot mvc自动配置(三)初始化mvc的组件的更多相关文章

  1. springboot mvc自动配置(目录)

    对于长时间基于spring框架做web开发的我们,springmvc几乎成为了开发普通web项目的标配.本系列文章基于快速启动的springboot,将从源码角度一点点了解springboot中mvc ...

  2. 全网最深分析SpringBoot MVC自动配置失效的原因

    前言 本来没有计划这一篇文章的,只是在看完SpringBoot核心原理后,突然想到之前开发中遇到的MVC自动失效的问题,虽然网上有很多文章以及官方文档都说明了原因,但还是想亲自看一看,本以为很简单的事 ...

  3. springboot mvc自动配置(一)自动配置DispatcherServlet和DispatcherServletRegistry

    所有文章 https://www.cnblogs.com/lay2017/p/11775787.html 正文 springboot的自动配置基于SPI机制,实现自动配置的核心要点就是添加一个自动配置 ...

  4. Springboot MVC 自动配置

    Springboot MVC 自动配置 官方文档阅读 https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#w ...

  5. spring-boot spring-MVC自动配置

    Spring MVC auto-configuration Spring Boot 自动配置好了SpringMVC 以下是SpringBoot对SpringMVC的默认配置:==(WebMvcAuto ...

  6. 关于SpringBoot的自动配置和启动过程

    一.简介 Spring Boot简化了Spring应用的开发,采用约定大于配置的思想,去繁从简,很方便就能构建一个独立的.产品级别的应用. 1.传统J2EE开发的缺点 开发笨重.配置繁多复杂.开发效率 ...

  7. 面试题: SpringBoot 的自动配置原理

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 3.Spring Boot 的自动配置原理 package com.mmall; import org. ...

  8. SpringBoot的自动配置

    1.根据条件来装配bean,SpringBoot的自动配置,根据条件进行自动配置. 首先创建一个接口,如下所示: package com.bie.encoding; /** * * @Descript ...

  9. springboot(六)自动配置原理和@Conditional

    官方参考的配置属性:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-appl ...

随机推荐

  1. sql数据库为null时候ASP语句判断问题

    我有一个表test1,有字段num,字段num有null值,也有空值,也有其他值,我要用asp语句判断我查询出来的num的值是否为null值.应该怎么写 严谨一点,要有两层判断: If IsNull( ...

  2. c语言 GPS nmealib学习笔记

    .nmealib简介 nmealib是一个基于C语言的用于nmea协议的开源库.虽然nmea体积小巧,但是却具备了不少功能. 分析NMEA语句并把结果保存在合适的C语言结构体中. 除了解析NMEA语句 ...

  3. Qt学习过程

    1.常用控件的使用[除了常见的还有QTableWidget.QTreeWidget...]2.信号与槽[需要知道connect函数的最后一个参数Qt::ConnectionType取不同枚举时的含义] ...

  4. jq删除标签

    <script>$(function(){ $("div").remove()})</script>

  5. python基础之知识补充-作用域、特殊语法

    python作用域 无函数的作用域 在python中没有块级作用域 什么叫块级作用域呢?先来看个例子: if 1 == 1: name= 'alex' print(name) 运行结果为alex 在j ...

  6. Tips for TMUX

    常用命令 tmux ls # 显示后台session列表 tmux new -t [name] # 新建session tmux a -t [name] # 进入session tmux kill-s ...

  7. Django文档

    https://docs.djangoproject.com/zh-hans/2.1/

  8. 【Leetcode_easy】784. Letter Case Permutation

    problem 784. Letter Case Permutation 参考 1. Leetcode_easy_784. Letter Case Permutation; 2. Grandyang; ...

  9. 【数据库开发】windows下hiredis的编译(主要是包括一些异步编程的错误)

    果然,高端的程序员真心是鸟都不鸟windows的,Redis的客户端找了一圈愣是没有C++的windows版本 我要做个windows上的C++的服务器都没办法和redis交互 github上所有能试 ...

  10. windows服务器入门 使用FileZilla搭建FTP服务

    下载FileZilla Server(注意:我搭建ftp的时候,有一个fz的版本会报错,百度了老半天都没有解决这个问题,回来我换了一个版本就可以.如果你们也出现了不知道怎么搞定的问题的话   可以考虑 ...