spring mvc DispatcherServlet解读

spring mvc DispatcherServlet解读

DispatcherServlet的继承和实现

IDEA按快捷键:ctrl+alt+u,就可以查看DispatcherServlet的继承的类和实现的接口。

从继承图可以得知:

  • DispatcherServlet本质是一个HttpServlet
  • HttpServletBean,FrameworkServlet,DispatcherServlet是属于SpringMVC的类

请添加图片描述

DispatcherServlet初始化

DispatcherServlet

DispatcherServlet看initStrategies(),该方法用于初始化各类解析器。

onRefresh(ApplicationContext context),该方法用于刷新策略

/**
	 * This implementation calls {@link #initStrategies}.
*/
//刷新策略
@Override
protected void onRefresh(ApplicationContext context) {
    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) {
    initMultipartResolver(context);    //初始化分段上传解析器
    initLocaleResolver(context);	   //初始化地域解析器
    initThemeResolver(context);		   //初始化主题解析器
    initHandlerMappings(context);	   //初始化处理器映射
    initHandlerAdapters(context);	   //初始化处理器适配器
    initHandlerExceptionResolvers(context);       //初始化处理器异常解析器
    initRequestToViewNameTranslator(context);     //初始化请求到视图名解析器
    initViewResolvers(context);        //初始化视图解析器
    initFlashMapManager(context);      //初始化快闪映射
}
FrameworkServlet

onRefresh(ApplicationContext context)重写于父类FrameworkServlet,点开FrameworkServlet,我们主要看看它initServletBean()方法,FrameworkServlet的onRefresh(ApplicationContext context)是个空实现,因为在DispatcherServlet实现了。

initServletBean()是重写HttpServletBean的initServletBean(),先看看initServletBean()干了什么:

  • 调用了initWebApplicationContext(),初始化了WebApplicationContext,而WebApplicationContext是继承于ApplicationContext接口的,所以我们知道了initWebApplicationContext是初始化了一个上下文。
  • 调用了initFrameworkServlet(),点开发现是个空实现。
@Override
	protected final void initServletBean() throws ServletException {
        //*******查看核心部分**********
		try {
            //这里初始化WebApplicationContext
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();   //空实现,给其他继承类实现
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}
		//*******其他日志的不看********
	}

点开initWebApplicationContext(),因为太长了,所以放图片。

上半段:

  • 通过servlet上下文中创建了一个rootcontext
  • 中间的if代码块在上下文刷新时才会运行,初始化状态时,webapplicationcontext是null,所以初始化时是不进入的。该段代码主要用于刷新上下文

请添加图片描述

下半段:

  • 查找已经存在的注册的上下文,如果没有就用rootContex去创建一样上下文。
  • refreshEventReceived默认是false
/** Flag used to detect whether onRefresh has already been called. */
private volatile boolean refreshEventReceived = false;
  • onRefresh()方法被重写了,所以我们知道在Dispatchservlet中,会初始化各种解析器(如:视图解析器等)

请添加图片描述

HttpServletBean

假设WEB-INF 目录下查找配置文件信息如下:

<!-- 部署 DispatcherServlet -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    <!-- 表示容器再启动时立即加载servlet -->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

HttpServletBean是抽象类,ctrl+F12查看方法。

请添加图片描述

找到init()方法,这个是我们要找到的重要方法

  • init()方法是重写了GenericServlet的init()方法,所以这个是最根本的初始化方法。

让我们看看init()干了什么:

ServletConfigPropertyValues是用来加载Servlet配置,ServletConfigPropertyValues是HttpServletBean的内部静态类,它负责取到web.xml中init-param(如:contextConfigLocation)

@Override
	public final void init() throws ServletException {
		//加载web.xml中init-param(如:contextConfigLocation)
		// Set bean properties from init parameters.
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        
		if (!pvs.isEmpty()) {
			try {
                //BeanWrapper将HttpServletBean进行包装
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                //ServletContext的资源加载器
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
                //注册资源编辑器
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
                //为HttpServletBean初始化包装,默认实现是空的
				initBeanWrapper(bw);
                //给包装类传递web.xml中init-param
				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()是交给子类实现的,FrameworkServlet实现了这个方法
		initServletBean();
	}
初始化总结

各类的初始化工作:

  • HttpServletBean 主要初始化web.xml资源
  • FrameworkServlet 获取servlet上下文创建WebApplicationContext
  • DispatcherServlet 初始化各类解析器

调用过程

  1. HttpServletBean ---- init()
  2. FrameworkServlet ---- initServletBean()
  3. FrameworkServlet ---- initWebApplicationContext()
  4. DispatcherServlet ---- onRefresh(ApplicationContext context)
  5. DispatcherServlet ---- initStrategies(ApplicationContext context)
  6. DispatcherServlet ---- initXXX(ApplicationContext context)各种解析器组件的初始化

DispatcherServlet处理请求

核心成员变量

DispatcherServlet的核心成员变量就是上面DispatcherServlet初始化中initStrategies(ApplicationContext context)初始化的各类处理器。

/** 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;

	/** 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;

	/** FlashMapManager used by this servlet. */
	@Nullable
	private FlashMapManager flashMapManager;

	/** List of ViewResolvers used by this servlet. */
	@Nullable
	private List<ViewResolver> viewResolvers;
doService()

在浏览器输入位置时,会触发DispatcherServletdoService(HttpServletRequest request, HttpServletResponse response)去处理请求。

doService(HttpServletRequest request, HttpServletResponse response)又会去调用doDispatch(HttpServletRequest request, HttpServletResponse response)去处理请求

请添加图片描述

doDispatch()

doDispatch比较多代码分成两段截图

上半段代码

请添加图片描述

下半段代码

请添加图片描述
还有
请添加图片描述

getHandler()

getHandler()会遍历所有的handlerMapping,并找出匹配的handler。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}
关于handlerMapping接口的实现类

handlerMapping接口的实现类有许多,RequestMappingHandlerMapping,该类用于创建@RequestMapping和@Controller注解的实例

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值