第二十五讲-控制器方法执行流程
第二十五讲-控制器方法执行流程
我们前面说了,对于HandlerAdapter最重要的功能就是执行控制器中的方法,那么控制器方法包含哪些部分呢?我们看一下下面的这张图;
HandlerMethod需要
-
bean即是哪个Controller
-
method即是Controller中的哪个方法
ServletInvocableHandlerMethod需要
- WebDataBinderFactory负责对象绑定、类型转换
- ParameterNameDiscoverer负责参数名解析
- HandlerMethodArgumentResolverComposite负责解析参数
- HandlerMethodReturnValueHandlerComposite负责处理返回值
看完了控制器的组成部分以后,我们再看一下控制器的执行流程:
其主要步骤分为三步:
- 准备参数(调用参数解析器组合器处理参数,完成参数解析,类型转换,数据绑定工作)
- 反射调用控制器方法
- 处理返回值(将反射调用获取到的结果通过返回值解析器组合器进行处理等,将结果放在ModelAndViewContainer,并将最终的ModelAndView响应给客户端)
接下来我们用代码演示一下:
public class A26 {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(WebConfig.class);
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
adapter.setApplicationContext(context);
adapter.afterPropertiesSet();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("name", "张三");
/*
现在可以通过 ServletInvocableHandlerMethod 把这些整合在一起, 并完成控制器方法的调用, 如下
*/
ServletInvocableHandlerMethod handlerMethod = new ServletInvocableHandlerMethod(
new WebConfig.Controller1(), WebConfig.Controller1.class.getMethod("foo", WebConfig.User.class));
// 添加处理绑定工厂
ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory(null, null);
// 为handlerMethod设置数据绑定工厂
handlerMethod.setDataBinderFactory(factory);
// 为handlerMethod设置参数名解析器
handlerMethod.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());
// 为handlerMethod设置方法参数名解析器组合器
handlerMethod.setHandlerMethodArgumentResolvers(getArgumentResolvers(context));
// 创建一个存储中间数据的容器ModelAndViewContainer
ModelAndViewContainer container = new ModelAndViewContainer();
// 获取模型工厂方法
Method getModelFactory = RequestMappingHandlerAdapter.class.getDeclaredMethod("getModelFactory", HandlerMethod.class, WebDataBinderFactory.class);
getModelFactory.setAccessible(true);
ModelFactory modelFactory = (ModelFactory) getModelFactory.invoke(adapter, handlerMethod, factory);
// 初始化模型数据
modelFactory.initModel(new ServletWebRequest(request), container, handlerMethod);
// 反射调用该控制器
handlerMethod.invokeAndHandle(new ServletWebRequest(request), container);
System.out.println(container.getModel());
context.close();
/*
学到了什么
a. 控制器方法是如何调用的
b. 模型数据如何产生
c. advice 之二, @ModelAttribute 补充模型数据
*/
}
// 方法参数名解析器组合器(包含常见的方法参数解析器)
public static HandlerMethodArgumentResolverComposite getArgumentResolvers(AnnotationConfigApplicationContext context) {
HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
composite.addResolvers(
new RequestParamMethodArgumentResolver(context.getDefaultListableBeanFactory(), false),
new PathVariableMethodArgumentResolver(),
new RequestHeaderMethodArgumentResolver(context.getDefaultListableBeanFactory()),
new ServletCookieValueMethodArgumentResolver(context.getDefaultListableBeanFactory()),
new ExpressionValueMethodArgumentResolver(context.getDefaultListableBeanFactory()),
new ServletRequestMethodArgumentResolver(),
new ServletModelAttributeMethodProcessor(false),
new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())),
new ServletModelAttributeMethodProcessor(true),
new RequestParamMethodArgumentResolver(context.getDefaultListableBeanFactory(), true)
);
return composite;
}
}
@Configuration
public class WebConfig {
@ControllerAdvice
static class MyControllerAdvice {
@ModelAttribute("a")
public String aa() {
return "aa";
}
}
@Controller
static class Controller1 {
@ModelAttribute("b")
public String aa() {
return "bb";
}
@ResponseStatus(HttpStatus.OK)
public ModelAndView foo(@ModelAttribute("u") User user) {
System.out.println("foo");
return null;
}
}
static class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
}
运行结果如下:
foo
{a=aa, b=bb, u=User{name='张三'}, org.springframework.validation.BindingResult.u=org.springframework.validation.BeanPropertyBindingResult: 0 errors}
11:31:27.616 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7e0ea639, started on Sun Aug 11 11:31:26 CST 2024
分类:
Spring 高级49讲
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构