spring源码的xml解析过程-5(springMvc)

spring mvc 初始化工作

org.springframework.web.servlet.FrameworkServlet#onApplicationEvent(ContextRefreshedEvent event) 监听到 ContextRefreshedEvent 事件时,则会调用子类中的 onRefresh(ApplicationContext context)initStrategies 方法进行初始化工作处理

org.springframework.web.servlet.DispatcherServlet.initStrategies

        initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);

initHandlerMappings 初始化
org.springframework.web.servlet.DispatcherServlet#initHandlerMappings

// 该属性可以web.xml中配置,默认为true
this.detectAllHandlerMappings

// 获取所有 HandlerMapping 接口的所有实现类
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

if (!matchingBeans.isEmpty()) {
// HandlerMapping 的所有实现类注册到 handlerMappings  集合容器中
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}


//  默认 handlerMappings  注册
	if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
		}

org.springframework.web.servlet.DispatcherServlet#getDefaultStrategies

String value = defaultStrategies.getProperty(key);

defaultStrategies 属性在静态块中进行了初始化

private static final Properties defaultStrategies;

static {

		try {
		// DispatcherServlet.properties 配置文件,该配置文件对springMVC 做了初始化工作的配置
			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());
		}
	}

springmvc.xml 中配置

<!--DefaultAnnotationHandlerMapping已过时,改为 
RequestMappingHandlerMapping-->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>

    <!--AnnotationMethodHandlerAdapter 已过时,改为 
    RequestMappingHandlerAdapter初始化 messageConverters 默认的消息转换器-->
<bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <!--消息转换器,在这里可以注册其它消息转换器-->
        <property name="messageConverters">
            <list>
                <ref bean="mappingJacksonHttpMessageConverter"/>
                <ref bean="stringHttpMessageConverter"/>
            </list>
        </property>
    </bean>
    
 <!-- StringHttpMessageConverter 默认编码为 ISO-8859-1 -->
    <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
        <property name="supportedMediaTypes" value="text/plain;charset=UTF-8"/>
    </bean>

    <!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
    <bean id="mappingJacksonHttpMessageConverter"
          class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/html;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
    </bean>   

配置 MappingJackson2HttpMessageConverter 参考

这两个类在 DispatcherServlet.properties 配置文件中做了默认配置,所以在springMvc.xml中可以不用配置该bean

  1. DefaultAnnotationHandlerMapping
  2. AnnotationMethodHandlerAdapter

request 请求实际上会先走到 javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 方法中。

在spring mvc 中则查看 org.springframework.web.servlet.FrameworkServlet#service 方法

HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
		if (HttpMethod.PATCH == httpMethod || httpMethod == null) {			//处理请求
			processRequest(request, response);
		}

org.springframework.web.servlet.FrameworkServlet#processRequest

doService(request, response);

spring mvc 请求流程
org.springframework.web.servlet.DispatcherServlet#doService

// 在 request 请求中存放相关信息 
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

//重点,spring mvc 的请求与响应过程
doDispatch(request, response);

springmvc请求响应流程
在这里插入图片描述

@RequestMapping 标记的方法会封装为 HandlerMethod 对象
HandlerMapping 就是 url 与 HandlerMethod 的映射关系
HandlerAdapter 负责调用具体Controller中的方法,HandlerAdapter 可以解析请求的方法参数、方法的返回值解析。用策略模式解析

org.springframework.web.servlet.DispatcherServlet#doDispatch

mappedHandler = getHandler(processedRequest);

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

org.springframework.web.servlet.DispatcherServlet#getHandler

// this.handlerMappings 容器在前面已经初始化过了,所以有值
	for (HandlerMapping hm : this.handlerMappings) {
	   // 查看 getHandler 方法
		HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}

org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler

Object handler = getHandlerInternal(request);

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal

HandlerMethod handlerMethod = 
lookupHandlerMethod(lookupPath, request);

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod

获取到方法上的所有相关配置信息
/query-student = {[/query-student],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}

// 获取到方法上的所有相关配置信息
List<T> directPathMatches = 
this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
	addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
  addMatchingMappings(this.mappingRegistry.getMappings().keySet(), 
  matches, request);
}

这个容器是是在什么时候初始化的?
MappingRegistry#mappingLookup
this.mappingRegistry.getMappings().keySet()

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet

    @Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods

// 循环容器中的所有bean
for (String beanName : beanNames) {
    // isHandler:过滤 @Controller,@RequestMapping 的bean
	if (beanType != null && isHandler(beanType)) {
		// beanName 就是 Controller 类的名称
		detectHandlerMethods(beanName);
	}
}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods

// 当前 controller 类
final Class<?> userType = ClassUtils.getUserClass(handlerType);

// 查询当前controller 类所有 @RequestMapping 注解标记的方法
	Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				new MethodIntrospector.MetadataLookup<T>() {
					@Override
					public T inspect(Method method) {
						try {
						   // 过滤 @RequestMapping 注解标记的方法
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					}
				});
	
	// 所有方法都注册到 MappingRegistry#mappingLookup 容器中			
	for (Map.Entry<Method, T> entry : methods.entrySet()) {
	  Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
	  T mapping = entry.getValue();
	  // 注册 HandlerMethod 逻辑
	  registerHandlerMethod(handler, invocableMethod, mapping);
	}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod

this.mappingRegistry.register(mapping, handler, method);

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register


// 往 MappingRegistry#mappingLookup 容器中注册信息
this.mappingLookup.put(mapping, handlerMethod);

List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
    // 注册
	this.urlLookup.add(url, mapping);
}

//跨域请求信息配置
CorsConfiguration corsConfig = 
initCorsConfiguration(handler, method, mapping);

this.mappingLookup
key: RequestMappingInfo
value:HandlerMethod

key:{[/query-student],methods=[],params=[],
headers=[],consumes=[],produces=[],custom=[]}

value: public java.util.Map com.dn.spring.controller.HelloWorldController.student(
java.lang.Integer)

this.urlLookup

key: /query-student
value: {[/query-student],methods=[],params=[],
headers=[],consumes=[],produces=[],custom=[]}

先根据请求url,在 this.urlLookup 获取 value
再根据 value 在 this.mappingLookup 获取 HandlerMethod
这个逻辑体现在 AbstractHandlerMethodMapping#getHandlerInternal 方法中HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

返回到
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler

// handler 其实就是 HandlerMethod
Object handler = getHandlerInternal(request);

// 将 HandlerMethod 和 拦截器集合 封装到 HandlerExecutionChain 
HandlerExecutionChain executionChain =
 getHandlerExecutionChain(handler, request);

返回到
org.springframework.web.servlet.DispatcherServlet#doDispatch
spring mvc 请求流程逻辑

//  HandlerExecutionChain 中有 HandlerMethod 和 拦截器集合
mappedHandler = getHandler(processedRequest);

// 将 HandlerMethod 做为参数传入 getHandlerAdapter 方法
// 得到 RequestMappingHandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 拦截器 前置执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
	return;
}

//(查看该方法)请求对应的方法调用
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// 拦截器 中置执行
mappedHandler.applyPostHandle(processedRequest, response, mv);

// 拦截器 后置执行
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle

return handleInternal(request, response, (HandlerMethod) handler);

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

mav = invokeHandlerMethod(request, response, handlerMethod);

RequestMappingHandlerAdapter#afterPropertiesSet 这里做了一些初始化工作

  1. 默认的参数解析器集合初始化:argumentResolvers
  2. 参数绑定解析器集合初始化:initBinderArgumentResolvers
  3. 方法返回值解析器集合初始化:returnValueHandlers

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

invocableMethod.invokeAndHandle(webRequest, mavContainer);

org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

// (查看该方法)请求方法执行的返回值
Object returnValue = 
invokeForRequest(webRequest, mavContainer, providedArgs);

try {
    // 方法返回值的类型转换处理
    this.returnValueHandlers.handleReturnValue(
	returnValue, getReturnValueType(returnValue), 
	mavContainer, webRequest);
}

org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest

// 解析请求方法的参数信息
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

//执行请求方法并得到方法的返回值
Object returnValue = doInvoke(args);

org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues

MethodParameter[] parameters = getMethodParameters()
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
    // 使用策略模式,得到当前参数的处理类
	if (this.argumentResolvers.supportsParameter(parameter)) {
		try {
		// 参数解析
		args[i] = this.argumentResolvers.resolveArgument(
		parameter, mavContainer, request, this.dataBinderFactory);
		continue;
		}
	}
}

@RequestBody 注解的参数解析
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor

// 支持的注解
@Override
public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(RequestBody.class);
	}

// 参数解析
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

//解析
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
}

org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#readWithMessageConverters

Object arg = readWithMessageConverters(inputMessage, parameter, paramType);

org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(org.springframework.http.HttpInputMessage, org.springframework.core.MethodParameter, java.lang.reflect.Type)

//获取请求类型
contentType = inputMessage.getHeaders().getContentType();

// 循环消息转转换器
// RequestMappingHandlerAdapter的无参构造器中加载默认的 HttpMessageConverter 实现类
// 在 RequestMappingHandlerAdapter#afterPropertiesSet 方法中加载
// 默认参数解析器时,将 HttpMessageConverter 的所有实现类传入到 
// RequestResponseBodyMethodProcessor 类的构造函数中,并传入到父类
// AbstractMessageConverterMethodArgumentResolver 中的属性messageConverters中 
// 所以在这里可以获取到所有注册的消息转换器实现类
for (HttpMessageConverter<?> converter : this.messageConverters) {
	//找到能处理该参数类型的消息转换器,会使用 StringHttpMessageConverter 类处理	
	if (converter.canRead(targetClass, contentType)) {
		body = 
		((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
	}
}

StringHttpMessageConverter 类
这里调用是父类中的方法 read
org.springframework.http.converter.AbstractHttpMessageConverter#read

   @Override
	public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
		return readInternal(clazz, inputMessage);
	}

org.springframework.http.converter.StringHttpMessageConverter#readInternal

    @Override
	protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
		Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
		// 读取输入流中的内容
		return StreamUtils.copyToString(inputMessage.getBody(), charset);
	}

入参 @RequestBody 参数解析,并没有使用json的消息转换器,而是使用了 StringHttpMessageConverter 消息转换器

返回到
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

//方法的返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

//返回值处理
this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue

//查看该方法,根据返回类型找到对应的处理器
HandlerMethodReturnValueHandler handler = 
selectHandler(returnValue, returnType);

//返回值类型的转换处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);

org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#selectHandler

// this.returnValueHandlers 是在
// RequestMappingHandlerAdapter#afterPropertiesSet 方法中初始化的
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
		return handler;
	}
}

返回到
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue

handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
  1. 查看 ViewNameMethodReturnValueHandler#handleReturnValue,当返回类型为字符串时,则返回到指定的页面

    	  if (returnValue instanceof CharSequence) {
    			String viewName = returnValue.toString();
    			mavContainer.setViewName(viewName);
    			if (isRedirectViewName(viewName)) {
    				mavContainer.setRedirectModelScenario(true);
    			}
    		}
    
  2. 查看 RequestResponseBodyMethodProcessor#handleReturnValue,当返回值有 @RequestBody 注解时,则不会返回页面

    //这里设置的值很重要
    mavContainer.setRequestHandled(true);
    

    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)

    	for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
    	((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
    }
    

    返回json 消息转换器 MappingJackson2HttpMessageConverter,
    查看 AbstractHttpMessageConverter#write方法 调用的是父类的
    org.springframework.http.converter.AbstractGenericHttpMessageConverter#write 方法

    writeInternal(t, outputMessage);
    

    org.springframework.http.converter.AbstractGenericHttpMessageConverter#writeInternal(T, org.springframework.http.HttpOutputMessage)

    writeInternal(t, null, outputMessage);
    

    org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal

    JsonGenerator generator =
     this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
    
    // 将返回值转换为json格式
    objectWriter.writeValue(generator, value);
    

返回到
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

invocableMethod.invokeAndHandle(webRequest, mavContainer);

//查看该方法
return getModelAndView(mavContainer, modelFactory, webRequest);

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelAndView

//可以看到为true时,则结束了,这里的值来自:RequestResponseBodyMethodProcessor#handleReturnValue 方法中的设置
// 不走视图模式
if (mavContainer.isRequestHandled()) {
	return null;
}

//走视图模式
ModelMap model = mavContainer.getModel();
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
		}
		return mav;

返回到
org.springframework.web.servlet.DispatcherServlet#doDispatch

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

org.springframework.web.servlet.DispatcherServlet#processDispatchResult

render(mv, request, response);

org.springframework.web.servlet.DispatcherServlet#render

// 找到视图解析器
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);

// 查看 InternalResourceView类
view.render(mv.getModelInternal(), request, response);

org.springframework.web.servlet.DispatcherServlet#resolveViewName

for (ViewResolver viewResolver : this.viewResolvers) {
// 找到视图解析器
View view = viewResolver.resolveViewName(viewName, locale);
}

InternalResourceView#render 调用的是父类的方法
org.springframework.web.servlet.view.AbstractView#render

renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);

org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel

// 请求页面的路径
String dispatcherPath = prepareForRendering(request, response);

RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);

// 调用转到页面的方法
rd.forward(request, response);

forward 、include、Rediect 参考

总结

  1. spring mvc 初始化工作
  2. spring mvc 请求与响应流程
    1. spring mvc 入参解析
    2. spring mvc 出参解析
    3. spring mvc 视图解析
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值