展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

Spring MVC入门(十二):DispatcherServlet初始化过程

  • SpringMVC常用组件
# DispatcherServlet:前端控制器,不需要工程师开发,由框架提供
作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
# HandlerMapping:处理器映射器,不需要工程师开发,由框架提供
作用:根据请求的url、method等信息查找Handler,即控制器方法
# Handler:处理器,需要工程师开发
作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
# HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供
作用:通过HandlerAdapter对处理器(控制器方法)进行执行
# ViewResolver:视图解析器,不需要工程师开发,由框架提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
# View:视图
作用:将模型数据通过页面展示给用户
  • DispatcherServlet初始化过程
DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet生命周期来进行调度
  • 查看源码
# 打开DispatcherServlet.java

# DispatcherServlet 继承自FrameworkServlet 
public class DispatcherServlet extends FrameworkServlet {

# FrameworkServlet 继承自HttpServletBean   
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

# HttpServletBean 继承自HttpServlet 
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {

# HttpServlet 继承自GenericServlet 
public abstract class HttpServlet extends GenericServlet {

# GenericServlet 实现Servlet接口
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {

# Servlet 接口
public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

# 查看GenericServlet重写了Servlet 接口中的初始化方法
  • 查看左侧重写带上箭头的表示重写了上级接口中的方法
# GenericServlet中初始化方法如下
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

# HttpServlet类中没有重写初始化方法

# 查看HttpServletBean类中的初始化方法,调用了initServletBean方法
	@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();
	}

# 查看initServletBean方法
protected void initServletBean() throws ServletException {
}

# 查看FrameworkServlet中的initServletBean方法,该类中的initServletBean方法重写的是HttpServletBean中的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;
		}

		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");
		}
	}

# 在initServletBean方法中执行如下初始化webApplicationContext 
try {
    this.webApplicationContext = initWebApplicationContext();
    initFrameworkServlet();
}

# 查看initWebApplicationContext方法,通过getWebApplicationContext获取WebApplicationContext ,之后判断是否为空,为空时执行createWebApplicationContext方法
	protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		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
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			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.
			synchronized (this.onRefreshMonitor) {
				onRefresh(wac);
			}
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
		}

		return wac;
	}

# 查看createWebApplicationContext方法,调用createWebApplicationContext方法
	protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
		return createWebApplicationContext((ApplicationContext) parent);
	}

# 查看createWebApplicationContext方法
	protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
		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");
		}
                // 创建ConfigurableWebApplicationContext 对象
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
                // spring和springmvc各自有1个容器,这里是将spring的ioc容器设置为springmvc的父容器
		wac.setParent(parent);
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
		configureAndRefreshWebApplicationContext(wac);
                // 最后返回该对象
		return wac;
	}

# 回到FrameworkServlet类的initWebApplicationContext方法中
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			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.
			synchronized (this.onRefreshMonitor) {
                                // 在上面createWebApplicationContext方法中创建好ConfigurableWebApplicationContext 对象后,刷新
				onRefresh(wac);
			}
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
                        // 将创建好的对象添加到共享域中
			getServletContext().setAttribute(attrName, wac);
		}

# 查看onRefresh方法
	protected void onRefresh(ApplicationContext context) {
		// For subclasses: do nothing by default.
	}

# 查看DispatcherServlet中的onRefresh方法,它重写的是FrameworkServlet类中的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);
	}
posted @ 2022-04-23 21:40  DogLeftover  阅读(42)  评论(0编辑  收藏  举报