01-IOC_init()

  • Servlet = server + applet(服务端小程序)
  • Servlet生命周期
    1. init()
    2. service()
    3. destroy()
  • Servlet关键类DispathcherServlet,关键配置web.xml
  • Tomcat第一件事加载web.xml

每写一个Servlet都要写以下原生配置,太麻烦

<!-- SpringMVC配置 -->
<!-- 配置DispatcherServlet -->
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 配置初始化参数,读取SpringMVC的核心配置文件 -->
    <!-- 不使用`<init-param>`,默认路径:/WEB-INF/<servlet-name>-servlet.xml -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring_mvc.xml</param-value>
    </init-param>

    <!-- 启动立即初始化servlet -->
    <load-on-startup>1</load-on-startup>
</servlet>
<!-- 映射路径为
        /:匹配所有资源,JSP除外
        /*:全部servlet + JSP
-->
<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>










 










 
 

  • SpringMVC是Spring的扩展,在启动SpringMVC前必须先把Spring容器启动起来
image-20240110091005854
  • web.xml是Tomcat进行加载、解析
  • SpringMVC继承Spring容器(两容器目的:隔离)。子容器可以使用父容器bean,父容器不能使用子容器

1. Spring容器创建

  • 入口:ContextLoaderListener#contextInitialized()
<!-- Spring配置 -->
<!-- ServletContext中添加Spring核心配置文件 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:application_context.xml</param-value>
</context-param>
<!-- 监听器,JAVAWEB项目中的ServletContext创建时,创建一个Spring的容器,放入ServletContext对象中 -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>




 



 

1. ContextLoaderListener

package org.springframework.web.context;

/**
 * Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
 * Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
 *
 * <p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
 * application context via the {@link #ContextLoaderListener(WebApplicationContext)}
 * constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
 * See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
 */
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

	public ContextLoaderListener() {
	}

	public ContextLoaderListener(WebApplicationContext context) {
		super(context);
	}


	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
	    // 1... ContextLoader
		initWebApplicationContext(event.getServletContext());
	}

	/**
	 * Close the root web application context.
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}

}



























 












image-20240110092626618

2. ContextLoader

  • spring-web模块下ContextLoader.properties
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-config.xml</param-value>
    </context-param>


 

package org.springframework.web.context;

/**
 * @see ContextLoaderListener
 * @see ConfigurableWebApplicationContext
 * @see org.springframework.web.context.support.XmlWebApplicationContext
 */
public class ContextLoader {

	/**
	 * Name of the class path resource (relative to the ContextLoader class)
	 * that defines ContextLoader's default strategy names.
	 */
	private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";

	private static final Properties defaultStrategies;

	/**
	 * The root WebApplicationContext instance that this loader manages.
	 */
	@Nullable
	private WebApplicationContext context;

	public static final String CONTEXT_CLASS_PARAM = "contextClass";

	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, ContextLoader.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
		}
	}

	/**
	 * Initialize Spring's web application context for the given servlet context,
	 * using the application context provided at construction time, or creating a new one
	 * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
	 * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
	 * @param servletContext current servlet context
	 * @return the new WebApplicationContext
	 * @see #ContextLoader(WebApplicationContext)
	 * @see #CONTEXT_CLASS_PARAM
	 * @see #CONFIG_LOCATION_PARAM
	 */
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			// web.xml中存在多次ContextLoader定义
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		servletContext.log("Initializing Spring root WebApplicationContext");
		Log logger = LogFactory.getLog(ContextLoader.class);
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
				// 1.. 初始化context,第一次执行的时候获取到一个root webApplicationcontext
                // Root WebApplicationContext, started on Thu Jan 01 08:00:00 CST 1970
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent ->
						// determine parent for root web application context, if any.
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					// 2.. 创建并且准备好了Spring容器
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			// 将创建的context对象记录在servletContext中
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;
			}
			else if (ccl != null) {
				currentContextPerThread.put(ccl, this.context);
			}

			if (logger.isInfoEnabled()) {
				long elapsedTime = System.currentTimeMillis() - startTime;
				logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
			}

			return this.context;
		}
		catch (RuntimeException | Error ex) {
			logger.error("Context initialization failed", ex);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
	}

	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
		// 1.. 获取contextClass的Class对象
		Class<?> contextClass = determineContextClass(sc);
		// 如果是自定义的contextClass对象,那么必须要实现ConfigurableWebApplicationContext此接口
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		// 2.
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

	protected Class<?> determineContextClass(ServletContext servletContext) {
        // 加载contextClass配置,一般无此配置
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); // contextClass
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
            // 1. XmlWebApplicationContext
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
			    // 2.
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}

		wac.setServletContext(sc);
        // contextConfigLocation => classpath:spring-config.xml
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
            // 1. Spring配置文件设置
			wac.setConfigLocation(configLocationParam);
		}

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}

		customizeContext(sc, wac);
        // 2. Spring.refresh()
		wac.refresh();
	}

}













 
















 
 






































 













 





























 






 
















 


 

























 


 












 



1. ContextLoader.properties

spring-web-5.2.2.RELEASE.jar/org/springframework/web/context/ContextLoader.properties

# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

3. XmlWebApplicationContext

image-20240110100407260
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {

	/** Default config location for the root context. */
	public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

	/** Default prefix for building a config location for a namespace. */
	public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

	/** Default suffix for building a config location for a namespace. */
	public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

}



 








  • Spring 的拓展方法
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
		implements ConfigurableWebApplicationContext, ThemeSource {

	public AbstractRefreshableWebApplicationContext() {
		setDisplayName("Root WebApplicationContext");
	}

	/**
	 * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
	 */
	@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
		beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

        // mvc增加session、request作用域
		WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
		WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
	}

	/**
	 * Initialize the theme capability.
	 */
	@Override
	protected void onRefresh() {
		this.themeSource = UiApplicationContextUtils.initThemeSource(this);
	}

}

















 
 











2. xml_MVC

Spring全家桶框架,都是一个框架在Spring框架基础之上做的延伸、扩展

  • ServletContextweb.xml整个配置
  • ServletConfig为某个Servlet的配置
  • DispatcherServlet.init()生命周期第一步,Tomcat调用执行
<!-- SpringMVC配置 -->
<!-- 配置DispatcherServlet -->
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 配置初始化参数,读取SpringMVC的核心配置文件 -->
    <!-- 不使用`<init-param>`,默认路径:/WEB-INF/<servlet-name>-servlet.xml -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring_mvc.xml</param-value>
    </init-param>

    <!-- 启动立即初始化servlet -->
    <load-on-startup>1</load-on-startup>
    <!--<async-supported>true</async-supported>-->
</servlet>
<!-- 映射路径为
        /:匹配所有资源,JSP除外
        /*:全部servlet + JSP
-->
<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>




 





 














image-20240110105503886

1. HttpServletBean#init()

  • 入口:DispatcherServlet#init()
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {

	@Nullable
	private ConfigurableEnvironment environment;

	private final Set<String> requiredProperties = new HashSet<>(4);

	/**
	 * Map config parameters onto bean properties of this servlet, and
	 * invoke subclass initialization.
	 * @throws ServletException if bean properties are invalid (or required
	 * properties are missing), or if subclass initialization fails.
	 */
	@Override
	public final void init() throws ServletException {

		// 1. Set bean properties from init parameters.
		//      将<servlet>中配置的<init-param>参数封装到pvs变量中。contextConfigLocation -> classpath:spring-mvc.xml
		//      GenericServlet#getServletConfig()
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				// 将当前的servlet对象转化成BeanWrapper对象,从而能够以spring的方法来将pvs注入到该beanWrapper中
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				// 注册自定义属性编辑器,一旦有Resource类型的属性,将会使用ResourceEditor进行解析
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				// 模板方法,可以在子类调用,做一些初始化工作,bw代表的是DispatcherServlet
				initBeanWrapper(bw);
				// 以spring的方式来将pvs注入到该beanWrapper对象中,将配置的初始化值(contextConfigLocation)设置到DispatcherServlet
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}

		// 2... FrameworkServlet. Let subclasses do whatever initialization they like.
		// 模板方法,子类初始化的入口方法。FrameworkServlet#initServletBean()
		initServletBean();
	}

}





 













 










 











 



2. FrameworkServlet

  • 195:wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

    /**
     * Default context class for FrameworkServlet.
     *
     * @see org.springframework.web.context.support.XmlWebApplicationContext
     */
    public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;

    /**
     * WebApplicationContext implementation class to create.
     */
    private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;

	/**
	 * Overridden method of {@link HttpServletBean}, invoked after any bean properties
	 * have been set. Creates this servlet's WebApplicationContext.
	 */
	@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 {
			// 1.. 创建或刷新WebApplicationContext实例并对servlet功能所使用的变量进行初始化
			this.webApplicationContext = initWebApplicationContext();
			// 模板方法,空实现,留给子类扩展
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (logger.isDebugEnabled()) {
			String value = this.enableLoggingRequestDetails ?
					"shown which may lead to unsafe logging of potentially sensitive data" :
					"masked to prevent unsafe logging of potentially sensitive data";
			logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
					"': request parameters and headers will be " + value);
		}

		if (logger.isInfoEnabled()) {
			logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
		}
	}

    /**
     * 一个原理,所有的前后端交互框架都是以servlet为基础,在使用SpringMVC时,默认把自己的容器设置成ServletContext的属性
     * 默认根容器的key为`WebApplicaitonContext.Root`,定义在WebApplicationContext中,调用ServletContext.getAttribute即可获取
     * <p>
     * Initialize and publish the WebApplicationContext for this servlet.
     * <p>Delegates to {@link #createWebApplicationContext} for actual creation
     * of the context. Can be overridden in subclasses.
     *
     * @return the WebApplicationContext instance
     * @see #FrameworkServlet(WebApplicationContext)
     * @see #setContextClass
     * @see #setContextConfigLocation
     */
    protected WebApplicationContext initWebApplicationContext() {
        // 1. **GenericServlet 获取Spring的root_webApplicationContext对象**
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        // 获得webApplicationContext wac对象
        WebApplicationContext wac = null;

        // 如果构造方法中已经传入webApplicationContext属性,则直接使用
        // 此方式主要用于servlet3.0之后的环境,Tomcat可以通过ServletContext.addServlet()注册servlet,此时就可以在创建FrameworkServlet和
        // 其子类的时候通过构造方法传递已经准备好的webApplicationContext
        if (this.webApplicationContext != null) { // skip
            // A context instance was injected at construction time -> use it
            wac = this.webApplicationContext;
            // 如果是ConfigurationWebApplicationContext类型,并且未激活,则进行初始化
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                // 未激活
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent -> set
                        // the root application context (if any; may be null) as the parent
                        cwac.setParent(rootContext);
                    }
                    // 配置和刷新上下文环境
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        // 从servletContext获取对应的webApplicationContext对象
        // 此方式需要在配置Servlet的时候将servletContext中的webApplicationContext的name配置到contextAttribute属性就可以
        if (wac == null) { // skip
            // No context instance was injected at construction time -> see if one
            // has been registered in the servlet context. If one exists, it is assumed
            // that the parent context (if any) has already been set and that the
            // user has performed any initialization such as setting the context id
            wac = findWebApplicationContext();
        }
        // 当前面两种方式都无效的情况下会创建一个webApplicationContext对象,一般情况下都是使用这样的方式
        if (wac == null) {
            // 2.. No context instance is defined for this servlet -> create a local one
            wac = createWebApplicationContext(rootContext);
        }

        // 将contextRefreshedEvent事件没有触发时调用此方法,模板方法,可以在子类重写
        if (!this.refreshEventReceived) {
            // Either the context is not a ConfigurableApplicationContext with refresh
            // support or the context injected at construction time had already been
            // refreshed -> trigger initial onRefresh manually here.
            synchronized (this.onRefreshMonitor) {
                onRefresh(wac);
            }
        }

        // 将applicationContext设置到servletContext中
        if (this.publishContext) {
            // Publish the context as a servlet context attribute.
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }

        return wac;
    }

	protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
        // 1..
		return createWebApplicationContext((ApplicationContext) parent);
	}

    protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
        // 1.. 获取servlet的初始化参数contextClass,默认为XmlWebApplicationContext.class
        Class<?> contextClass = getContextClass();
        // 如果非ConfigurableWebApplicationContext类型,抛出ConfigurableWebApplicationContext异常
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException(
                    "Fatal initialization error in servlet with name '" + getServletName() +
                            "': custom WebApplicationContext class [" + contextClass.getName() +
                            "] is not of type ConfigurableWebApplicationContext");
        }
        // 2. 通过反射方式实例化contextClass
        ConfigurableWebApplicationContext wac =
                (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

        // 设置environment
        wac.setEnvironment(getEnvironment());
        // 3. **parent为Spring_ApplicationContext**
        wac.setParent(parent);
        // 获取contextConfigLocation属性,配置在servlet初始化参数中
        String configLocation = getContextConfigLocation();
        if (configLocation != null) {
            // 4. 将设置的contextConfigLocation参数传给wac,默认传入WEB-INFO/servletName-servlet.xml
            wac.setConfigLocation(configLocation);
        }
        // 5.. 配置和初始化wac
        configureAndRefreshWebApplicationContext(wac);

        return wac;
    }

	/**
	 * Return the custom context class.
	 */
	public Class<?> getContextClass() {
		return this.contextClass; // XmlWebApplicationContext
	}

    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        // 如果wac使用了默认编号,则重新设置id属性
        if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
            // The application context id is still set to its original default value
            // -> assign a more useful id based on available information
            // 使用contextId属性
            if (this.contextId != null) {
                wac.setId(this.contextId);
            }
            // 自动生成
            else {
                // Generate default id...
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                        ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
            }
        }

        // 1. 设置wac的servletContext、servletConfig、namespace属性
        wac.setServletContext(getServletContext());
        wac.setServletConfig(getServletConfig());
        wac.setNamespace(getNamespace());
        // 2. 添加监听器SourceFilteringListener到wac中,实际监听的是ContextRefreshListener所监听的事件,监听ContextRefreshedEvent事件,
        // 当接收到消息之后会调用onApplicationEvent(),调用onRefresh(),并将refreshEventReceived标志设置为true,表示已经refresh过
        wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

        // The wac environment's #initPropertySources will be called in any case when the context
        // is refreshed; do it eagerly here to ensure servlet property sources are in place for
        // use in any post-processing or initialization that occurs below prior to #refresh
        // 3. 获取环境对象并且添加相关的属性
        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
        }

        // 此处为空方法,不做任何实现。可拓展
        postProcessWebApplicationContext(wac);
        // 4.. 执行自定义初始化context
        applyInitializers(wac);
        // 5. 刷新wac,从而初始化wac
        wac.refresh();
    }

    protected void applyInitializers(ConfigurableApplicationContext wac) {
        // web.xml中加载<context-param>,<param-name>globalInitializerClasses</param-name>
        String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);
        if (globalClassNames != null) {
            for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
                this.contextInitializers.add(loadInitializer(className, wac));
            }
        }

        if (this.contextInitializerClasses != null) {
            for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses,
                    INIT_PARAM_DELIMITERS)) {
                this.contextInitializers.add(loadInitializer(className, wac));
            }
        }

        AnnotationAwareOrderComparator.sort(this.contextInitializers);
        for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
            // 1. SpringBoot里有initializer
            initializer.initialize(wac);
        }
    }

}







 




 
















 





































 






































 
























 




 









 




 




 


 





























 




 





 







 

 





















 




3. MVC_refresh()_finishRefresh()

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {

            // Prepare this context for refreshing.
            /*
             * 前戏,做容器刷新前的准备工作
             * 1. 设置容器的启动时间
             * 2. 设置关闭标志位为false,激活标志位为true
             * 3. 设置Environment,并加载当前系统的属性值到Environment
             * 4. 准备监听器、事件集合,Spring默认为空
             */
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            /*
             * 1. 创建容器对象:DefaultListableBeanFactory
             * 2. 加载xml到BF => BeanDefinition
             */
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // BF前戏,各种属性填充`add(), register()`
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                /*
                 * 1. 模板方法,后续拓展
                 * 2. 子类重写做额外的处理,查看web中的代码,有具体实现的
                 */
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                /*
                 * 1. 实例化 & 执行BFPP
                 * 2. 首次getBean()
                 */
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                /*
                 * 1. 实例化前戏
                 * 2. 实例化 & 注册BPP。真正调用是getBean()
                 */
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                /*
                 * 1. 国际化处理。为上下文初始化message源,即不同语言消息体
                 * 2. SpringMVC,国际化的代码重点讲
                 */
                initMessageSource();

                // Initialize event multicaster for this context.
                /*
                 * 1. 实例化前戏
                 * 2. init Multicaster(多路广播器),用于bean各阶段事件监听
                 */
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // 模板方法,后续拓展
                onRefresh();

                // Check for listener beans and register them.
                /*
                 * 1. 实例化前戏
                 * 2. 注册监听器。bean中查找listener_bean,注册到消息广播器中
                 */
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 1. 生命周期处理器lifecycleProcessor初始化并onRefresh
                // 2. 发布ContextRefreshEvent
                finishRefresh();
            } catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                // 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
                destroyBeans();

                // Reset 'active' flag.
                // 重置active标志
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            } finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

    /**
     * 完成刷新
     * Finish the refresh of this context, invoking the LifecycleProcessor's
     * onRefresh() method and publishing the
     * {@link org.springframework.context.event.ContextRefreshedEvent}.
     */
    protected void finishRefresh() {
        // 1. Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        // 2. 默认DefaultLifecycleProcessor
        initLifecycleProcessor();

        // 3. Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();

        // 4.. Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        // 5. LiveBeansView: Spring用于支持JMX服务
        LiveBeansView.registerApplicationContext(this);
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        // 1..
        publishEvent(event, null);
    }

    /**
     * 将给定事件发布到所有监听器
     * <p>
     * Publish the given event to all listeners.
     *
     * @param event     the event to publish (may be an {@link ApplicationEvent}
     *                  or a payload object to be turned into a {@link PayloadApplicationEvent})
     * @param eventType the resolved event type, if known
     * @since 4.2
     */
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        // 如果event为null,抛出异常
        Assert.notNull(event, "Event must not be null");

        // Decorate event as an ApplicationEvent if necessary
        ApplicationEvent applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent) event;
        } else {
            // PayloadApplicationEvent:携带任意有效负载的ApplicationEvent
            applicationEvent = new PayloadApplicationEvent<>(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
            }
        }

        // Multicast right now if possible - or lazily once the multicaster is initialized
        // 如果可能的话,现在就进行组播——或者在组播初始化后延迟
        // earlyApplicationEvents:在多播程序设置之前发布的ApplicationEvent
        // 如果earlyApplicationEvents不为null,这种情况只在上下文的多播器还没有初始化的情况下才会成立,会将applicationEvent
        // 添加到earlyApplicationEvents保存起来,待多博器初始化后才继续进行多播到适当的监听器
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
            // 1... SimpleApplicationEventMulticaster 多播applicationEvent到适当的监听器
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }

        // Publish event via parent context as well...
        // 通过父上下文发布事件
        // 如果parent不为null
        if (this.parent != null) {
            // 如果parent是AbstractApplicationContext的实例
            if (this.parent instanceof AbstractApplicationContext) {
                // 将event多播到所有适合的监听器。如果event不是ApplicationEvent实例,会将其封装成PayloadApplicationEvent对象再进行多播
                ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
            } else {
                // 通知与event事件应用程序注册的所有匹配的监听器
                this.parent.publishEvent(event);
            }
        }
    }

}

















































































 










































 









 





































 


















1. SimpleAppEventMulticaster

SourceFilteringListener来源

  1. FrameworkServlet#configureAndRefreshWebApplicationContext() => ApplicationContext
    • wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
  2. AbstractApplicationContext#registerListeners() => Multicaster
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    /**
     * 广播事件
     *
     * @param event     the event to multicast
     * @param eventType the type of event (can be {@code null})
     */
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        // 如果eventType不为null就引用eventType;否则将event转换为ResolvableType对象再引用
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        // 获取此多播器的当前任务线程池
        Executor executor = getTaskExecutor();
        // getApplicationListeners方法是返回与给定事件类型匹配的应用监听器集合
        // 遍历获取所有支持event的监听器
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            // 如果executor不为null
            if (executor != null) {
                // 使用executor回调listener的onApplicationEvent方法,传入event
                executor.execute(() -> invokeListener(listener, event));
            } else {
                // 1.. 回调listener的onApplicationEvent方法,传入event
                invokeListener(listener, event);
            }
        }
    }

    /**
     * 使用给定的事件调用给定的监听器
     * <p>
     * Invoke the given listener with the given event.
     *
     * @param listener the ApplicationListener to invoke
     * @param event    the current event to propagate
     * @since 4.1
     */
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        // 获取此多播器的当前错误处理程序
        ErrorHandler errorHandler = getErrorHandler();
        // 如果errorHandler不为null
        if (errorHandler != null) {
            try {
                // 回调listener的onApplicationEvent方法,传入event
                doInvokeListener(listener, event);
            } catch (Throwable err) {
                // 交给errorHandler接收处理err
                errorHandler.handleError(err);
            }
        } else {
            // 1.. 回调listener的onApplicationEvent方法,传入event
            doInvokeListener(listener, event);
        }
    }

    /**
     * 回调listener的onApplicationEvent方法,传入 event
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            // 1.. 传入event
            // ContextRefreshListener#onApplicaitonEvent() => FrameworkServlet.this.onApplicationEvent()
            listener.onApplicationEvent(event);
        } catch (ClassCastException ex) {
            // 获取异常信息
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception and just log a debug message.
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            } else {
                // 抛出异常
                throw ex;
            }
        }
    }

}























 



























 











 


















2. SourceFilteringListener

  • FrameworkServlet
  • 195: wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
public class SourceFilteringListener implements GenericApplicationListener, SmartApplicationListener {

	@Nullable
	private GenericApplicationListener delegate;

	public SourceFilteringListener(Object source, ApplicationListener<?> delegate) {
		this.source = source;
		this.delegate = (delegate instanceof GenericApplicationListener ?
				(GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
	}

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event.getSource() == this.source) {
		    // 1..
			onApplicationEventInternal(event);
		}
	}

	protected void onApplicationEventInternal(ApplicationEvent event) {
		if (this.delegate == null) {
			throw new IllegalStateException(
					"Must specify a delegate object or override the onApplicationEventInternal method");
		}
		// 1... GenericApplicationListenerAdapter
		this.delegate.onApplicationEvent(event);
	}

}








 






 









 



1. GenericAppListenerAdapter
public class GenericApplicationListenerAdapter implements GenericApplicationListener, SmartApplicationListener {

	private final ApplicationListener<ApplicationEvent> delegate;

	/**
	 * Create a new GenericApplicationListener for the given delegate.
	 * @param delegate the delegate listener to be invoked
	 */
	@SuppressWarnings("unchecked")
	public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
		Assert.notNull(delegate, "Delegate listener must not be null");
		this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
		this.declaredEventType = resolveDeclaredEventType(this.delegate);
	}

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
	    // 1... FrameworkServlet$ContextRefreshListener
		this.delegate.onApplicationEvent(event);
	}

}


















 



2. ContextRefreshListener
@SuppressWarnings("serial")
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

	/**
	 * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
	 * only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
	 */
	private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

		@Override
		public void onApplicationEvent(ContextRefreshedEvent event) {
		    // 1..
			FrameworkServlet.this.onApplicationEvent(event);
		}
	}

	/**
	 * Callback that receives refresh events from this servlet's WebApplicationContext.
	 * <p>The default implementation calls {@link #onRefresh},
	 * triggering a refresh of this servlet's context-dependent state.
	 * @param event the incoming ApplicationContext event
	 */
	public void onApplicationEvent(ContextRefreshedEvent event) {
		this.refreshEventReceived = true;
		synchronized (this.onRefreshMonitor) {
			// 1... DispatcherServlet
			onRefresh(event.getApplicationContext());
		}
	}

}












 













 




3. DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {

	private static final Properties defaultStrategies;

	/**
	 * Name of the class path resource (relative to the DispatcherServlet class)
	 * that defines DispatcherServlet's default strategy names.
	 */
	private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

	/**
     * Well-known name for the LocaleResolver object in the bean factory for this namespace.
     */
    public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

	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);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
		}
	}

    /**
     * multipart数据文件处理器
     * MultipartResolver used by this servlet.
     */
    @Nullable
    private MultipartResolver multipartResolver;

    /**
     * 语言处理器,提供国际化的支持
     * LocaleResolver used by this servlet.
     */
    @Nullable
    private LocaleResolver localeResolver;

    /**
     * 主题处理器,设置需要应用的整体格式
     * ThemeResolver used by this servlet.
     */
    @Nullable
    private ThemeResolver themeResolver;

    /**
     * 处理器匹配器,返回请求对应的处理器和拦截器
     * List of HandlerMappings used by this servlet.
     */
    @Nullable
    private List<HandlerMapping> handlerMappings;

    /**
     * 处理器适配器,用于执行处理器
     * <p>
     * List of HandlerAdapters used by this servlet.
     */
    @Nullable
    private List<HandlerAdapter> handlerAdapters;

    /**
     * 异常处理器,用于解析处理器发生的异常
     * List of HandlerExceptionResolvers used by this servlet.
     */
    @Nullable
    private List<HandlerExceptionResolver> handlerExceptionResolvers;

    /**
     * 视图名称转换器
     * RequestToViewNameTranslator used by this servlet.
     */
    @Nullable
    private RequestToViewNameTranslator viewNameTranslator;

    /**
     * FlashMap管理器,负责重定向保存参数到临时存储(默认session)中
     * FlashMapManager used by this servlet.
     */
    @Nullable
    private FlashMapManager flashMapManager;

    /**
     * 视图解析器,根据视图名称和语言,获取View视图
     * List of ViewResolvers used by this servlet.
     */
    @Nullable
    private List<ViewResolver> viewResolvers;

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

	/**
	 * Initialize the strategy objects that this servlet uses.
	 * <p>May be overridden in subclasses in order to initialize further strategy objects.
	 */
	protected void initStrategies(ApplicationContext context) {
		// 1. MultipartResolver:处理文件上传。可自定义
		initMultipartResolver(context);
		// 2.. LocaleResolver:处理国际化配置
		// 		基于URL参数配置(AcceptHeaderLocaleResolver),基于session配置(SessionLocaleResolver),基于cookie配置(CookieLocaleResolver)
		initLocaleResolver(context);
		// 3. ThemeResolver:设置主题Theme
		initThemeResolver(context);
		// 4. HandlerMapping:映射器,用来将对应的Request跟Controller进行对应
		initHandlerMappings(context);
		// 5. HandlerAdapter:处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器
		initHandlerAdapters(context);
		// 6. HandlerExceptionResolver:基于HandlerExceptionResolver接口的异常处理
		initHandlerExceptionResolvers(context);
		// 7. RequestToViewNameTranslator
		//      当Controller没有返回View对象或逻辑视图名称,并且没有直接往Response输出流写数据时,Spring将会采用约定方式提供一个逻辑视图名称
		initRequestToViewNameTranslator(context);
		// 8. ViewResolver:将ModelAndView选择合适的视图进行渲染的处理器
		initViewResolvers(context);
		// 9. FlashMapManager:提供请求存储属性,供其他请求使用
		initFlashMapManager(context);
	}

	/**
	 * Initialize the LocaleResolver used by this class.
	 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
	 * we default to AcceptHeaderLocaleResolver.
	 */
	private void  initLocaleResolver(ApplicationContext context) {
		try {
			// 1. IOC中取localeResolver对象,取不到抛异常
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Detected " + this.localeResolver);
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			// 2.. 从DispatcherServlet.properties配置文件中获取
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
						"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
			}
		}
	}

	protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
	    // 1..
		List<T> strategies = getDefaultStrategies(context, strategyInterface);
		if (strategies.size() != 1) {
			throw new BeanInitializationException(
					"DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
		}
		// 2.
		return strategies.get(0);
	}

	@SuppressWarnings("unchecked")
	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		// 1. 获得strategyInterface对应的value值
		String key = strategyInterface.getName();
		// 2. 创建value对应的对象们,并返回
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			// 基于","分隔,创建classNames数组
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			// 创建strategyInterface集合
			List<T> strategies = new ArrayList<>(classNames.length);
			// 遍历classNames数组,创建对应的类,添加到strategyInterface中
			for (String className : classNames) {
				try {
					// 3. 获得className类
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					// 4.. 创建className对应的类,并添加到strategies中
					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(
							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
							className + "] for interface [" + key + "]", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<>();
		}
	}

    protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
        // 1... AbstractAutowireCapableBeanFactory => DefaultListableBeanFactory
        return context.getAutowireCapableBeanFactory().createBean(clazz);
    }

}








 











 
 












































































 







 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 










 










 









 





 





 

 









 

 






















 



1. DispatcherServlet.properties
  • 源码环境properties会覆盖。jar形式不会覆盖

spring-webmvc/org.springframework.web.servlet/resources/DispatcherServlet.properties

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager








 



 





 





 


	/**
	 * Initialize the MultipartResolver used by this class.
	 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
	 * no multipart handling is provided.
	 */
	private void initMultipartResolver(ApplicationContext context) {
		try {
			// IOC中获取MultipartResolver的Bean
			this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Detected " + this.multipartResolver);
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Default is no multipart resolver.
			this.multipartResolver = null;
			if (logger.isTraceEnabled()) {
				logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
			}
		}
	}

	/**
	 * Initialize the LocaleResolver used by this class.
	 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
	 * we default to AcceptHeaderLocaleResolver.
	 */
	private void  initLocaleResolver(ApplicationContext context) {
		try {
			// 1. IOC中取localeResolver对象,取不到抛异常
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Detected " + this.localeResolver);
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			// 2.. 从DispatcherServlet.properties配置文件中获取
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
						"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
			}
		}
	}

	/**
	 * Initialize the ThemeResolver used by this class.
	 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
	 * we default to a FixedThemeResolver.
	 */
	private void initThemeResolver(ApplicationContext context) {
		try {
			this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Detected " + this.themeResolver);
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			// 从配置文件中获取默认的FixedThemeResolver
			this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No ThemeResolver '" + THEME_RESOLVER_BEAN_NAME +
						"': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
			}
		}
	}

	/**
	 * Initialize the HandlerMappings used by this class.
	 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
	 * we default to BeanNameUrlHandlerMapping.
	 */
	private void initHandlerMappings(ApplicationContext context) {
		// 将handlerMappings置空
		this.handlerMappings = null;

		// 如果开启探测功能,则扫描已注册的HandlerMapping的bean,添加到handlerMappings中
		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			// 扫描已注册的handlerMapping的bean
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			// 添加到handlerMappings中,并进行排序
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order. 可以定义多种视图,按照优先级进行排序操作
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		// 如果关闭探测功能,则获取Bean名称为handlerMapping对应的bean,将其添加到handlerMappings
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		// 如果未获得到,则获得默认配置的handlerMapping类
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

	/**
	 * Initialize the HandlerAdapters used by this class.
	 * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
	 * we default to SimpleControllerHandlerAdapter.
	 */
	private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
				// We keep HandlerAdapters in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}

		// Ensure we have at least some HandlerAdapters, by registering
		// default HandlerAdapters if no other adapters are found.
		// 如果未获得到,则获得默认配置的HandlerAdapter类
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

	/**
	 * Initialize the HandlerExceptionResolver used by this class.
	 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
	 * we default to no exception resolver.
	 */
	private void initHandlerExceptionResolvers(ApplicationContext context) {
		// 置空 handlerExceptionResolver 处理
		this.handlerExceptionResolvers = null;

		// 自动扫描handlerExceptionResolver类型的bean
		if (this.detectAllHandlerExceptionResolvers) {
			// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
					.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
				// We keep HandlerExceptionResolvers in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
			}
		}
		// 获取名字为HANDLER_EXCEPTION_RESOLVER_BEAN_NAME的bean
		else {
			try {
				HandlerExceptionResolver her =
						context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
				this.handlerExceptionResolvers = Collections.singletonList(her);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, no HandlerExceptionResolver is fine too.
			}
		}

		// Ensure we have at least some HandlerExceptionResolvers, by registering
		// default HandlerExceptionResolvers if no other resolvers are found.
		// 如果未获得到,则获取默认配置的handlerExceptionResolver类
		if (this.handlerExceptionResolvers == null) {
			this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

	/**
	 * Initialize the RequestToViewNameTranslator used by this servlet instance.
	 * <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
	 */
	private void initRequestToViewNameTranslator(ApplicationContext context) {
		try {
			this.viewNameTranslator =
					context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Detected " + this.viewNameTranslator);
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			// 如果未找到,则获取默认的 RequestToViewNameTranslator 对象,DefaultRequestToViewNameTranslator
			this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
						"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
			}
		}
	}

	/**
	 * Initialize the ViewResolvers used by this class.
	 * <p>If no ViewResolver beans are defined in the BeanFactory for this
	 * namespace, we default to InternalResourceViewResolver.
	 */
	private void initViewResolvers(ApplicationContext context) {
		// 置空 viewResolvers 处理
		this.viewResolvers = null;

		/// 自动扫描 ViewResolver 类型的 Bean
		if (this.detectAllViewResolvers) {
			// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
			Map<String, ViewResolver> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.viewResolvers = new ArrayList<>(matchingBeans.values());
				// We keep ViewResolvers in sorted order.
				AnnotationAwareOrderComparator.sort(this.viewResolvers);
			}
		}
		// 获得名字为VIEW_RESOLVER_BEAN_NAME的bean
		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.
			}
		}

		// Ensure we have at least one ViewResolver, by registering
		// a default ViewResolver if no other resolvers are found.
		// 如果未获得到,则获取默认配置的ViewResolver对象
		if (this.viewResolvers == null) {
			this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

	/**
	 * Initialize the {@link FlashMapManager} used by this servlet instance.
	 * <p>If no implementation is configured then we default to
	 * {@code org.springframework.web.servlet.support.DefaultFlashMapManager}.
	 */
	private void initFlashMapManager(ApplicationContext context) {
		try {
			this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Detected " + this.flashMapManager);
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			// 未找到,则获取默认的 FlashMapManager 对象,SessionFlashMapManager
			this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +
						"': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
			}
		}
	}








 
























 










 














 










 





















 










 











 


















 








 











 




















 










 











 














 










 




















 









 











 














 










 






4. AbsAutowireCapableBF
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    @Override
    @SuppressWarnings("unchecked")
    public <T> T createBean(Class<T> beanClass) throws BeansException {
        // Use prototype bean definition, to avoid registering bean as dependent bean.
        // 封装RootBeanDefinition
        RootBeanDefinition bd = new RootBeanDefinition(beanClass);
        // 设置bean的作用域
        bd.setScope(SCOPE_PROTOTYPE);
        // 是否允许被缓存
        bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
        return (T) createBean(beanClass.getName(), bd, null);
    }

}








 




 



3. boot_MVC

image-20241025111529981
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\


 

1. WebMvcAutoConfiguration

package org.springframework.boot.autoconfigure.web.servlet;

/**
 * {@link EnableAutoConfiguration Auto-configuration} for {@link EnableWebMvc Web MVC}.
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

	public static final String DEFAULT_PREFIX = "";

	public static final String DEFAULT_SUFFIX = "";

	private static final String[] SERVLET_LOCATIONS = { "/" };


	// ---------------------------------------------------------------------------------------------

	// Defined as a nested config to ensure WebMvcConfigurer is not read when not
	// on the classpath
	@Configuration(proxyBeanMethods = false)
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {

		private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);

		private final ResourceProperties resourceProperties;

		private final WebMvcProperties mvcProperties;

		@Bean
		@ConditionalOnMissingBean
		public InternalResourceViewResolver defaultViewResolver() {
			InternalResourceViewResolver resolver = new InternalResourceViewResolver();
			resolver.setPrefix(this.mvcProperties.getView().getPrefix());
			resolver.setSuffix(this.mvcProperties.getView().getSuffix());
			return resolver;
		}

		@Bean
		@ConditionalOnBean(View.class)
		@ConditionalOnMissingBean
		public BeanNameViewResolver beanNameViewResolver() {
			BeanNameViewResolver resolver = new BeanNameViewResolver();
			resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
			return resolver;
		}

		@Bean
		@ConditionalOnBean(ViewResolver.class)
		@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
		public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
			ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
			resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
			// ContentNegotiatingViewResolver uses all the other view resolvers to locate
			// a view so it should have a high precedence
			resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
			return resolver;
		}

		@Bean
		@ConditionalOnMissingBean
		@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
		public LocaleResolver localeResolver() {
			if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
				return new FixedLocaleResolver(this.mvcProperties.getLocale());
			}
			AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
			localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
			return localeResolver;
		}

	}

    // ---------------------------------------------------------------------------------------------

	/**
	 * Configuration equivalent to {@code @EnableWebMvc}.
	 */
	@Configuration(proxyBeanMethods = false)
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

		private final ResourceProperties resourceProperties;

		private final WebMvcProperties mvcProperties;

		private final ListableBeanFactory beanFactory;

		private final WebMvcRegistrations mvcRegistrations;

		private ResourceLoader resourceLoader;

		public EnableWebMvcConfiguration(ResourceProperties resourceProperties,
				ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
				ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
			this.resourceProperties = resourceProperties;
			this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
			this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
			this.beanFactory = beanFactory;
		}

		@Bean
		@Override
		public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
				@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
				@Qualifier("mvcConversionService") FormattingConversionService conversionService,
				@Qualifier("mvcValidator") Validator validator) {
			RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
					conversionService, validator);
			adapter.setIgnoreDefaultModelOnRedirect(
					this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
			return adapter;
		}

    }

}










 





























 









 








 














 







































 









2. WebMvcConfigurationSupport

image-20241025111854301
package org.springframework.web.servlet.config.annotation;

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {

	private static final boolean romePresent;
	private static final boolean jaxb2Present;
	private static final boolean jackson2Present;
	private static final boolean jackson2XmlPresent;
	private static final boolean jackson2SmilePresent;
	private static final boolean jackson2CborPresent;
	private static final boolean gsonPresent;
	private static final boolean jsonbPresent;

	static {
		ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
		romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
		jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
		jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
				ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
		jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
		jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
		jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
		gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
		jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
	}

	@Nullable
	private ApplicationContext applicationContext;

	@Nullable
	private ServletContext servletContext;

	@Nullable
	private List<Object> interceptors;

	@Nullable
	private PathMatchConfigurer pathMatchConfigurer;

	@Nullable
	private ContentNegotiationManager contentNegotiationManager;

	@Nullable
	private List<HandlerMethodArgumentResolver> argumentResolvers;

	@Nullable
	private List<HandlerMethodReturnValueHandler> returnValueHandlers;

	@Nullable
	private List<HttpMessageConverter<?>> messageConverters;

	@Nullable
	private Map<String, CorsConfiguration> corsConfigurations;

	/**
	 * Return a {@link RequestMappingHandlerMapping} ordered at 0 for mapping
	 * requests to annotated controllers.
	 */
	@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
		mapping.setOrder(0);
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setContentNegotiationManager(contentNegotiationManager);
		mapping.setCorsConfigurations(getCorsConfigurations());

		PathMatchConfigurer configurer = getPathMatchConfigurer();

		Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
		if (useSuffixPatternMatch != null) {
			mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
		}
		Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
		if (useRegisteredSuffixPatternMatch != null) {
			mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
		}
		Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
		if (useTrailingSlashMatch != null) {
			mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
		}

		UrlPathHelper pathHelper = configurer.getUrlPathHelper();
		if (pathHelper != null) {
			mapping.setUrlPathHelper(pathHelper);
		}
		PathMatcher pathMatcher = configurer.getPathMatcher();
		if (pathMatcher != null) {
			mapping.setPathMatcher(pathMatcher);
		}
		Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
		if (pathPrefixes != null) {
			mapping.setPathPrefixes(pathPrefixes);
		}

		return mapping;
	}

	/**
	 * Protected method for plugging in a custom subclass of
	 * {@link RequestMappingHandlerMapping}.
	 * @since 4.0
	 */
	protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
		return new RequestMappingHandlerMapping();
	}

	/**
	 * Return a {@link BeanNameUrlHandlerMapping} ordered at 2 to map URL
	 * paths to controller bean names.
	 */
	@Bean
	public BeanNameUrlHandlerMapping beanNameHandlerMapping(
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
		mapping.setOrder(2);
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setCorsConfigurations(getCorsConfigurations());
		return mapping;
	}

	/**
	 * Returns a {@link RequestMappingHandlerAdapter} for processing requests
	 * through annotated controller methods. Consider overriding one of these
	 * other more fine-grained methods:
	 * <ul>
	 * <li>{@link #addArgumentResolvers} for adding custom argument resolvers.
	 * <li>{@link #addReturnValueHandlers} for adding custom return value handlers.
	 * <li>{@link #configureMessageConverters} for adding custom message converters.
	 * </ul>
	 */
	@Bean
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcValidator") Validator validator) {

		RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
		adapter.setContentNegotiationManager(contentNegotiationManager);
		adapter.setMessageConverters(getMessageConverters());
		adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
		adapter.setCustomArgumentResolvers(getArgumentResolvers());
		adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

		if (jackson2Present) {
			adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
			adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}

		AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
		configureAsyncSupport(configurer);
		if (configurer.getTaskExecutor() != null) {
			adapter.setTaskExecutor(configurer.getTaskExecutor());
		}
		if (configurer.getTimeout() != null) {
			adapter.setAsyncRequestTimeout(configurer.getTimeout());
		}
		adapter.setCallableInterceptors(configurer.getCallableInterceptors());
		adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

		return adapter;
	}

	/**
	 * Protected method for plugging in a custom subclass of
	 * {@link RequestMappingHandlerAdapter}.
	 * @since 4.3
	 */
	protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
		return new RequestMappingHandlerAdapter();
	}

	/**
	 * Returns a {@link HandlerExceptionResolverComposite} containing a list of exception
	 * resolvers obtained either through {@link #configureHandlerExceptionResolvers} or
	 * through {@link #addDefaultHandlerExceptionResolvers}.
	 * <p><strong>Note:</strong> This method cannot be made final due to CGLIB constraints.
	 * Rather than overriding it, consider overriding {@link #configureHandlerExceptionResolvers}
	 * which allows for providing a list of resolvers.
	 */
	@Bean
	public HandlerExceptionResolver handlerExceptionResolver(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
		configureHandlerExceptionResolvers(exceptionResolvers);
		if (exceptionResolvers.isEmpty()) {
			addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
		}
		extendHandlerExceptionResolvers(exceptionResolvers);
		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
		composite.setOrder(0);
		composite.setExceptionResolvers(exceptionResolvers);
		return composite;
	}

	/**
	 * A method available to subclasses for adding default
	 * {@link HandlerExceptionResolver HandlerExceptionResolvers}.
	 * <p>Adds the following exception resolvers:
	 * <ul>
	 * <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through
	 * {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.
	 * <li>{@link ResponseStatusExceptionResolver} for exceptions annotated with
	 * {@link org.springframework.web.bind.annotation.ResponseStatus}.
	 * <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring exception types
	 * </ul>
	 */
	protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers,
			ContentNegotiationManager mvcContentNegotiationManager) {

		ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
		exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
		exceptionHandlerResolver.setMessageConverters(getMessageConverters());
		exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
		exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
		if (jackson2Present) {
			exceptionHandlerResolver.setResponseBodyAdvice(
					Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}
		if (this.applicationContext != null) {
			exceptionHandlerResolver.setApplicationContext(this.applicationContext);
		}
		exceptionHandlerResolver.afterPropertiesSet();
		exceptionResolvers.add(exceptionHandlerResolver);

		ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
		responseStatusResolver.setMessageSource(this.applicationContext);
		exceptionResolvers.add(responseStatusResolver);

		exceptionResolvers.add(new DefaultHandlerExceptionResolver());
	}

	/**
	 * Protected method for plugging in a custom subclass of
	 * {@link ExceptionHandlerExceptionResolver}.
	 * @since 4.3
	 */
	protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
		return new ExceptionHandlerExceptionResolver();
	}

}

















 
 












































 










































 











 






















 







 
 






















 
















 























 














 












 



3. DispatcherServletAutoCfg

/**
 * {@link EnableAutoConfiguration Auto-configuration} for the Spring
 * {@link DispatcherServlet}. Should work for a standalone application where an embedded
 * web server is already present and also for a deployable application using
 * {@link SpringBootServletInitializer}.
 *
 * @author Phillip Webb
 * @author Dave Syer
 * @author Stephane Nicoll
 * @author Brian Clozel
 * @since 2.0.0
 */
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

	/*
	 * The bean name for a DispatcherServlet that will be mapped to the root URL "/"
	 */
	public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

	/*
	 * The bean name for a ServletRegistrationBean for the DispatcherServlet "/"
	 */
	public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

	@Configuration(proxyBeanMethods = false)
	@Conditional(DefaultDispatcherServletCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
	protected static class DispatcherServletConfiguration {

		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
			DispatcherServlet dispatcherServlet = new DispatcherServlet();
			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
			dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
			dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
			return dispatcherServlet;
		}

		@Bean
		@ConditionalOnBean(MultipartResolver.class)
		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
		public MultipartResolver multipartResolver(MultipartResolver resolver) {
			// Detect if the user has created a MultipartResolver but named it incorrectly
			return resolver;
		}

	}

}






















 














 



















4. BeanWrapper

@Test
public void beanWrapperImpl() {
    Ooxx build = Ooxx.builder()
            .id(1).build();

    BeanWrapperImpl beanWrapper = new BeanWrapperImpl(build);

    // 1. 一个个setter()
    beanWrapper.setPropertyValue("id", 2);
    beanWrapper.setPropertyValue("name", 2);

    // 2. map_setter()
    Map<String, Integer> map = Map.of("id", 2, "name", 2);
    beanWrapper.setPropertyValues(map);

    // 3. PV_setter()
    PropertyValue pv1 = new PropertyValue("id", 2);
    PropertyValue pv2 = new PropertyValue("name", 2);
    beanWrapper.setPropertyValue(pv1);
    beanWrapper.setPropertyValue(pv2);

    // 4. list_setter()
    List<PropertyValue> pvList = List.of(pv1, pv2);
    MutablePropertyValues pvs = new MutablePropertyValues(pvList);
    beanWrapper.setPropertyValues(pvs);

    System.out.println("build = " + build);
}





 


 




 


 

 



 
 
 



public class TestBeanWrapper {

    public static void main(String[] args) {
        User user = new User();

        // BeanWrapper是Spring中的核心接口,是Spring中的一个包装类
        // 具有单独或批量获取、设置属性值,获取属性描述符以及查询属性可读可写的能力,还可以完成类型的转换
        BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(user);
        beanWrapper.setPropertyValue("name", "ooxx");
        System.out.println("user.getName() = " + user.getName());

        PropertyValue value = new PropertyValue("name", "xxoo");
        beanWrapper.setPropertyValue(value);
        System.out.println("user.getName() = " + user.getName());
    }
}


class User {

    private String name;

    public String getName() {
        return name;
    }

    // 必须有setter()
    public void setName(String name) {
        this.name = name;
    }
}