Spring MVC原理学习笔记

学习来源:黑马程序员

学习时间:2023年11月4日

image-20231014174625911

1 DispatcherServlet

1.1 初始化时机

代码准备

参见:[[Spring原理#2.2.4 AnnotationConfigServletWebServerApplicationContext]]

1
2
3
4
5
6
7
@Slf4j
public class A20 {
public static void main(String[] args) {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Configuration
@ComponentScan
public class WebConfig {

// Web容器的工厂
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory(9090);
}

// DispatcherServlet
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}

// 注册DispatcherServlet,Spring MVC的入口
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
// 将dispatcherServlet注册到web容器中(这里是tomcat)
// 拦截路径设置为 /
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}

}

默认情况下,DispatcherServlet在接收到第一次请求时进行初始化操作,实际上是调用到了下面的onRefresh方法:

1
2
3
4
// DispatcherServlet初始化方法
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}

image-20231207171731511

image-20231207171814272

访问时,打印日志:

image-20231207172026225


可以设置为当Tomcat启动时就初始化DispatcherServlet

1
2
3
4
5
6
7
8
9
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
// 将dispatcherServlet注册到web容器中(这里是tomcat)
// 拦截路径设置为 /
DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");
// 启动服务器时就初始化
registrationBean.setLoadOnStartup(1);
return registrationBean;
}

打印结果:

image-20231207172108615

1.2 初始化方法

初始化方法:

1
2
3
4
// DispatcherServlet初始化方法
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}

onRefresh又调用了initStrategies

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 初始化各个组件
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
// 路径映射器
this.initHandlerMappings(context);
// 适配不同形式的控制器方法
this.initHandlerAdapters(context);
// 异常处理
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}

注意:初始化时,这些默认添加组件不会作为bean,不会出现在容器里。

1.3 RequestMappingHandlerMapping

  • RequestMappingHandlerMapping,中文翻译为处理器映射器
  • 作用:解析@RequestMapping注解及其派生注解(例如@GetMapping@PostMapping),生成路径与控制器方法的映射关系
  • 映射关系的生成时机:DispatcherServlet初始化时,即执行onRefresh方法时。
  • 映射关系由一个Map存储,键为请求方法,值为请求路径

代码演示

  • 控制器类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Slf4j
@Controller
public class Controller1 {
@GetMapping("/test1")
public ModelAndView test1() {
log.debug("test1()");
return null;
}

@PostMapping("/test2")
public ModelAndView test2(@RequestParam("name") String name) {
log.debug("test2({})", name);
return null;
}

@PutMapping("/test3")
public ModelAndView test3(@Token String token) {
log.debug("test3({})", token);
return null;
}

@RequestMapping("/test4.yml")
@Yml
public User1 test4() {
log.debug("test4()");
return new User1("Hongyi", 23);
}
}
  • 启动类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Slf4j
public class A20 {
public static void main(String[] args) throws Exception {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
// 作用:解析@RequestMapping注解及其派生注解,生成路径 与 控制器方法的映射关系
// 时机:DispatcherServlet初始化时就生成该映射关系
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 映射结果
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
handlerMethods.forEach((k, v) -> {
System.out.println(k + "=" + v);
});

// 模拟请求到来,获取控制器方法
// 返回结果被封装为一个处理器执行链对象
HandlerExecutionChain chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/test1"));
System.out.println(chain);
}
}

打印结果:

image-20231207180104005

1.4