Spring MVC(三)-----FrameworkServlet

目录

  • 推荐公众号
  • 引言
  • 上一篇
  • 正文
    • initServletBean
    • initWebApplicationContext
    • findWebApplicationContext
    • createWebApplicationContext
    • configureAndRefreshWebApplicationContext

推荐公众号

有彩蛋哦!!!(或者公众号内点击网赚获取彩蛋)
程序员探索之路

引言

HttpServletBean完成的工作非常简单,FrameworkServlet完成的工作也不复杂,主要就是创建SpringMVC的IOC容器。但是debug 没有配置文件的springboot项目发现,最要的工作还是调用了DispatcherServlet重写的onRefresh方法

上一篇

Spring MVC(二)-----HttpServletBean
https://blog.csdn.net/yueloveme/article/details/89643980

正文

FrameworkServlet类的设计目的就是用来建立一个和Servlet关联的Spring容器上下文并将其注册到ServletContext中。
debug过程中没有遇到需要FrameworkServlet来创建容器的情况,在AbstractApplicationContext中refresh方法中创建Spring的IOC容器是在SpringMVC初始化之前进行的,而且并不是项目启动就会初始化SpringMVC而是第一次调用的时候会进行初始化,这是目前观察到的如有不正确欢迎指正

initServletBean

/**
	 * 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 FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			this.webApplicationContext = initWebApplicationContext();
			无具体实现
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (this.logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

initWebApplicationContext

/**
	 * Initialize and publish the WebApplicationContext for this servlet.
	 * 

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 */ 初始化和发布web应用上下文 protected WebApplicationContext initWebApplicationContext() { 获取Spring的IOC容器 SpringIOC容器是先于SpringMVC容器创建的,要把rootContext 当做父容器 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; 如果webApplicationContext已经不为空,表示这个Servlet类是通过编程式注册到容器中的 (Servlet 3.0 +中的ServletContext.addServlet()),上下文也由编程式传入。若这个传 入的上下文还没有被初始化,将rootContext上下文设置为它的父上下文,然后将其初始化,否 则直接使用。 if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; 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); } } } if (wac == null) { // 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 如果为空,说明该Servlet不是由编程式注册到容器中的,在ServletContext中 查找上下文,查找得到 说明上下文已经以别的方式初始化并注册在contextAttribute下,直接使用 wac = findWebApplicationContext(); } if (wac == null) { // No context instance is defined for this servlet -> create a local one 此时还为空,调用以下方法创建一个全新的以rootContext为父上下文的上下 文,作为SpringMVC配置元素的上下文 wac = createWebApplicationContext(rootContext); } 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. DispatcherServlet具体实现,初始化一系列属性 onRefresh(wac); } if (this.publishContext) { // Publish the context as a servlet context attribute. 将这个上下文发布到ServletContext中 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; }

findWebApplicationContext

从当前容器中查找SpringMVC容器
/**
	 * Retrieve a {@code WebApplicationContext} from the {@code ServletContext}
	 * attribute with the {@link #setContextAttribute configured name}. The
	 * {@code WebApplicationContext} must have already been loaded and stored in the
	 * {@code ServletContext} before this servlet gets initialized (or invoked).
	 * 

Subclasses may override this method to provide a different * {@code WebApplicationContext} retrieval strategy. * @return the WebApplicationContext for this servlet, or {@code null} if not found * @see #getContextAttribute() */ @Nullable protected WebApplicationContext findWebApplicationContext() { String attrName = getContextAttribute(); if (attrName == null) { return null; } WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName); if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: initializer not registered?"); } return wac; }

createWebApplicationContext

创建SpringMVC容器
/**
	 * Instantiate the WebApplicationContext for this servlet, either a default
	 * {@link org.springframework.web.context.support.XmlWebApplicationContext}
	 * or a {@link #setContextClass custom context class}, if set.
	 * 

This implementation expects custom contexts to implement the * {@link org.springframework.web.context.ConfigurableWebApplicationContext} * interface. Can be overridden in subclasses. *

Do not forget to register this servlet instance as application listener on the * created context (for triggering its {@link #onRefresh callback}, and to call * {@link org.springframework.context.ConfigurableApplicationContext#refresh()} * before returning the context instance. * @param parent the parent ApplicationContext to use, or {@code null} if none * @return the WebApplicationContext for this servlet * @see org.springframework.web.context.support.XmlWebApplicationContext */ protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { Class<?> contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]"); } 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"); } 实例化IOC容器 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); 设置IOC容器相关属性 wac.setEnvironment(getEnvironment()); 设置parent wac.setParent(parent); String configLocation = getContextConfigLocation(); if (configLocation != null) { wac.setConfigLocation(configLocation); } 初始化springMVC各种的相关配置,各种注入的Controller,配置文件 configureAndRefreshWebApplicationContext(wac); return wac; }

configureAndRefreshWebApplicationContext

配置或者刷新应用上下文
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		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
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
			}
		}
		设置SpringMVC 属性
		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		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
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);
		初始化springMVC各种的相关配置,各种注入的Controller,配置文件
		wac.refresh();
	}

你可能感兴趣的:(SpingMVC)