SpringMVC之分析RequestMappingHandlerAdapter(二)

本文深入探讨了SpringMVC中的RequestMappingHandlerAdapter组件,重点分析了处理请求参数和返回值的方法。介绍了默认参数解析器和返回值处理器的初始化过程。

接上篇文章,我们在这一篇文章中继续对RequestMappingHandlerAdapter这个类进行分析。在上篇文章中我们说到afterPropertiesSet这个方法中添加的一些MethodHandlerResolver,我们继续分析这个方法中的其他代码:

		if (this.initBinderArgumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
在我们做表单提交的时候可能需要对一些特殊值进行转换,比如时间格式,金钱等,这个时候我们可能会用到InitBinder这个注解,来添加一些特殊的编辑器。上面这几段代码的意思是,需要对哪些类型的请求映射处理方法的参数注册一些特殊的编辑器。如果我们没有配置过initBinderArgumentResolvers 这个属性的值的话,那么它会去getDefaultInitBinderArgumentResolvers这个方法中默认的一些参数解析器。如下所示:

	private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());
		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		//自定义的参数解析器
		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}
		// Catch-all
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		return resolvers;
	}
自定义的参数解析器,也会被添加到这个集合中,initBinderArgumentResolvers 这个类也是为托给HandlerMethodArgumentResolverComposite这个类来处理的。如果我们设置了initBinderArgumentResolvers 的话,那么它只会取我们设置的参数解析器。

下面我们再看一下returnValueHandlers返回值的处理器。我们在做项目的时候,有时候返回的是一个页面,有时候返回的是一个字符串,有时候返回的是JSON对象(静态资源除外),这些不同的返回值的处理是通过一些HandlerMethodReturnValueHandler的实现类来做的,这个我们以后会找几个常用的HandlerMethodReturnValueHandler实现类来分析一下,SpringMVC大概给我们默认了这么多的返回值处理器:

		if (this.returnValueHandlers == null) {
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
SpringMVC默认的returnValueHandler

	private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
		List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

		// Single-purpose return value types
		//返回一个ModelAndView
		handlers.add(new ModelAndViewMethodReturnValueHandler());
		handlers.add(new ModelMethodProcessor());
		handlers.add(new ViewMethodReturnValueHandler());
		handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
		handlers.add(new StreamingResponseBodyReturnValueHandler());
		handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
				this.contentNegotiationManager, this.requestResponseBodyAdvice));
		handlers.add(new HttpHeadersReturnValueHandler());
		handlers.add(new CallableMethodReturnValueHandler());
		handlers.add(new DeferredResultMethodReturnValueHandler());
		handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
		// Annotation-based return value types
		handlers.add(new ModelAttributeMethodProcessor(false));
		//有RequestBody和ResponseBody注解的方法
		handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
				this.contentNegotiationManager, this.requestResponseBodyAdvice));
		// Multi-purpose return value types
		//直接返回一个字符,注意这个字符串是不带ResponseBody注解的
		handlers.add(new ViewNameMethodReturnValueHandler());
		handlers.add(new MapMethodProcessor());
		// Custom return value types
		//自定义的返回值处理器
		if (getCustomReturnValueHandlers() != null) {
			handlers.addAll(getCustomReturnValueHandlers());
		}
		// Catch-all
		if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
			handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
		}
		else {
			handlers.add(new ModelAttributeMethodProcessor(true));
		}

		return handlers;
	}

这个returnValueHandlers 是HandlerMethodReturnValueHandlerComposite这个对象的实例。

在上面的分析中有一点需要我们注意的是,我们将HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler、HttpMessageConverter等放到了相应的集合中,这个放入的顺序是很重要的。

我们在做SpringMVC开发的时候,只需要在SpringMVC的配置文件中添加这么一句话 <mvc:annotation-driven/>,就可以进行正常的Web开发的工作。那么RequestMappingHandlerAdapter、RequestMappingHandlerMapping等这些类是什么时候注入到Spring的Bean容器的呢?我们在下一篇的文章中会进行说明。


### Spring MVC 框架架构组成 Spring MVC 是基于请求驱动的 Web 框架,采用了经典的前端控制器模式进行设计。它由多个核心组件构成,这些组件协同工作以处理 HTTP 请求并返回响应。 #### 核心组件及功能 1. **前端控制器(DispatcherServlet)** DispatcherServlet 是整个框架的入口点,负责接收所有的 HTTP 请求,并协调各个组件之间的交互。它是整个流程的核心控制单元[^5]。 2. **处理器映射(HandlerMapping)** HandlerMapping 接口(如 `RequestMappingHandlerMapping`)根据 URL 找到对应的 Controller 方法。这个过程涉及对注解(例如 `@RequestMapping`)的解析和匹配。 3. **处理器适配器(HandlerAdapter)** HandlerAdapter 接口(如 `RequestMappingHandlerAdapter`)负责调用 Controller 中的方法,并处理参数绑定、数据转换以及返回值的处理。它可以支持多种类型的控制器方法,包括基于注解的方法[^5]。 4. **视图解析器(ViewResolver)** ViewResolver 接口(如 `InternalResourceViewResolver`)用于将逻辑视图名称解析为实际的视图对象(如 JSP 页面)。它决定了如何呈现最终的响应内容[^5]。 5. **异常处理器(HandlerExceptionResolver)** HandlerExceptionResolver 接口(如 `DefaultHandlerExceptionResolver`)用于捕获和处理 Controller 抛出的异常,并提供统一的错误响应机制。开发者可以自定义异常处理器来实现更复杂的错误处理逻辑[^3]。 6. **区域解析器(LocaleResolver)** LocaleResolver 用于解析客户端的区域设置,以便提供国际化支持。它可以识别用户的语言偏好,并据此返回相应的本地化内容。 7. **主题解析器(ThemeResolver)** ThemeResolver 负责管理应用程序的主题样式,允许根据用户的选择或系统配置动态更改界面外观。 8. **Multipart 解析器(MultipartResolver)** MultipartResolver 用于处理文件上传请求,能够解析 multipart/form-data 类型的数据,并将其转换为易于处理的对象形式。 --- ### Spring MVC 的工作原理 Spring MVC 的工作流程主要围绕 DispatcherServlet 展开,其核心调度逻辑如下: 1. **请求进入 DispatcherServlet** 所有的 HTTP 请求首先被 DispatcherServlet 捕获。在 `doService()` 方法中,会初始化一些上下文属性,然后调用 `doDispatch(request, response)` 进行进一步处理[^5]。 2. **确定处理器(Handler)** DispatcherServlet 使用 HandlerMapping 查找与当前请求 URL 匹配的 Controller 方法。这一过程可能涉及到 URL 参数的匹配和注解的解析。 3. **调用处理器适配器** 一旦找到合适的 Controller 方法,DispatcherServlet 就会委托给相应的 HandlerAdapter 来执行该方法。HandlerAdapter 会处理方法参数的绑定、类型转换以及方法调用。 4. **处理业务逻辑** Controller 方法通常包含具体的业务逻辑,可能会访问数据库或其他服务层组件来获取或操作数据。 5. **生成模型和视图** Controller 方法执行完毕后,会返回一个 ModelAndView 对象,其中包含了模型数据和视图名称。DispatcherServlet 随后使用 ViewResolver 将视图名称解析为实际的视图对象。 6. **渲染视图并返回响应** 最后,DispatcherServlet 将模型数据传递给视图进行渲染,并通过 HttpServletResponse 返回最终的 HTML 或其他格式的响应。 在整个过程中,如果发生异常,DispatcherServlet 会调用 HandlerExceptionResolver 来处理这些异常,并返回适当的错误页面或 JSON 响应。 --- ### 示例代码:简单的 Spring MVC 控制器 以下是一个简单的 Spring MVC 控制器示例,展示了如何定义一个处理 GET 请求的 Controller 方法。 ```java import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class HelloController { @GetMapping("/hello") @ResponseBody public String sayHello() { return "Hello, World!"; } } ``` 在这个例子中: - `@Controller` 注解标记了该类为一个 Spring MVC 控制器。 - `@GetMapping` 注解指定了该方法处理 `/hello` 路径上的 GET 请求。 - `@ResponseBody` 注解表示该方法直接返回字符串作为响应体,而不是视图名称。 --- ### 总结 Spring MVC 提供了一个灵活且强大的 Web 开发框架,通过分离关注点(即 Model、View 和 Controller),使得开发人员可以更容易地构建可维护和可扩展的应用程序。它的核心组件相互协作,确保每个请求都能得到正确处理,并生成预期的响应。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值