Spring MVC中DispatchServlet原理讲解(二)

为什么Springboot能够在没有XML文件的情况下注入DispatchServlet对象,主要是依靠DispatcherServletAutoConfiguration 这个配置类,该配置类位于org.springframework.boot.autoconfigure.web.servlet 这个包的下面,该配置类的上面有三个注解:

@AutoConfigureOrder(-2147483648)
@AutoConfiguration(
    after = {ServletWebServerFactoryAutoConfiguration.class}
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({DispatcherServlet.class})

1.@AutoConfigureOrder:value为加载的顺序,顺序越小越早加载,负数也可以。

2.@AutoConfiguration:表示根据spring.factories文件自动装载,其中的after参数表示要在某个类装载之后才能装载。

3.@ConditionalOnWebApplication:表示只有Spring为web服务的时候,该类才能生效,其中type代表着web服务的类型。

4.@ConditionalOnClass:表示当项目中存在某个类时,该类才能生效,value为某个类的class对象。

从上面的注解可以看出,当我们创建的Srping应用为SERVLET类型的web服务,且当前的项目中包含DispatcherServlet类时,该类才能当做配置类加载到Spring的IOC容器中。

DispatcherServletAutoConfiguration 这个配置类中包含有四个子类:

1. DispatcherServletRegistrationCondition:用于表示 DispatcherServletRegistration 注入时的条件。

2. DefaultDispatcherServletCondition:用于表示默认的DisPatcherServlet对象的注入条件。

3.DispatcherServletRegistrationConfiguration: 用于将DispatcherServletRegistration对象注入到IOC容器中。

4. DispatcherServletConfiguration: 用于将DispatcherServlet对象注入到IOC容器中。

通过全局搜索可知DispatcherServlet类位于 org.springframework.web.servlet 包中。

DispatcherServlet 的构造函数有两种:

public DispatcherServlet() {
	this.setDispatchOptionsRequest(true);
}

public DispatcherServlet(WebApplicationContext webApplicationContext) {
	super(webApplicationContext);
	this.setDispatchOptionsRequest(true);
}

其中带参的构造函数主要是为了传入多个Servlet共享的Web上下文。

在 DispatcherServlet 类中有一个onRefresh方法,该方法在Springboot启动过程中刷新上下文的时候会运行的时候会运行,源码如下所示:

protected void onRefresh(ApplicationContext context) {
	this.initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    // 初始化文件上传解析器
    //文件上传解析器作用:对上传的文件数据进行解析
	this.initMultipartResolver(context);
    // 初始化地区解析器
    // 地区解析器作用:通过上传的请求解析客户端所在的地区,实现多语言即国际化
	this.initLocaleResolver(context);
    // 初始化主题解析器
    // 主题解析器作用:用于解析客户端所使用Spring主题,将参数转化为对应的值传给前端
	this.initThemeResolver(context);
    // 初始化映射处理器
    // 映射处理器作用:根据请求中的url找到对应的处理器链(HandlerExecutionChain,1个处理器+多个拦截器)
	this.initHandlerMappings(context);
    // 初始化适配处理器
    // 适配处理器作用:用于执行处理器对象中的处理方法,并将处理后的结果包装成ModelView类型的对象返回
	this.initHandlerAdapters(context);
    // 初始化异常处理器
    // 异常处理器作用:用于处理处理请求的过程中发生的异常,返回一个ModelView对象
	this.initHandlerExceptionResolvers(context);
    // 初始化视图转换器
    // 视图转换器作用:根据请求解析对应视图的名称,用于填充ModeAndView中的view成员变量
	this.initRequestToViewNameTranslator(context);
    // 初始化视图解析器
    // 视图解析器作用:将ModelAndView中视图的名称解析成View对象,然后赋值给view成员变量,最终DispatcherServlet会调用View对象中的render方法,将对应的视图返回给前端
	this.initViewResolvers(context);
    // 用于在重定向之前存储一些数据,重定向之后也可以获取
	this.initFlashMapManager(context);
}

由源码可以看出,DispatcherServlet的onRefresh方法主要是将ApplicationContext(IOC容器)中一些有用的对象加载到成员变量中。

DispatcherServlet主要是在doDispatch方法中调用上述初始化的对象,doDispatch的源码如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	HandlerExecutionChain mappedHandler = null;
	boolean multipartRequestParsed = false;
	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

	try {
		try {
			ModelAndView mv = null;
			Object dispatchException = null;

			try {
				processedRequest = this.checkMultipart(request);
				multipartRequestParsed = processedRequest != request;
				// 根据请求获取对应的处理器链
				mappedHandler = this.getHandler(processedRequest);
				if (mappedHandler == null) {
					this.noHandlerFound(processedRequest, response);
					return;
				}

				// 根据处理器获取适配器
				HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				// 执行拦截器中的preHandle()方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// 利用适配器调用处理器中的处理方法来处理请求(Conreoller中的方法),并且返回一个ModelAndView对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				
				// 根据请求获取视图的名称(调用视图解析器)
				this.applyDefaultViewName(processedRequest, mv);
				// 执行拦截器中的postHandle()方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			} catch (Exception var20) {
				dispatchException = var20;
			} catch (Throwable var21) {
				dispatchException = new NestedServletException("Handler dispatch failed", var21);
			}
			
			// 调用拦截器中的afterCompletion()方法,并且调用了View对象的render()方法将视图返回给前端
			this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
		} catch (Exception var22) {
			// 内部调用了afterCompletion()方法,就算报异常也会调用afterCompletion()方法
			this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
		} catch (Throwable var23) {
			// 内部调用了afterCompletion()方法,就算报异常也会调用afterCompletion()方法
			this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
		}

	} finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			if (mappedHandler != null) {
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			}
		} else if (multipartRequestParsed) {
			this.cleanupMultipart(processedRequest);
		}

	}
}

在Web上下文中还存在着一些前置过滤器和后置过滤器,因此SpringMVC在处理请求的过程中,前置过滤器会对请求进行预处理,然后再交给DispatcherServlet对象处理,后置过滤器会在视图返回给用户之前对响应进行预处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值