- DispatcherServlet 的初始化时机
- DispatcherServlet 初始化都做了什么
- RequestMappingHandlerMapping 基本用途
- RequestMappingHandlerAdapter 基本用途
- RequestMappingHandlerAdapter 自定义参数和返回值处理器
DispatcherServlet
DispatcherServlet 的初始化时机
要观察 DispatcherServlet 的初始化时机过程,我们自己内嵌 WEB 容器配置类和支持内嵌 WEB 容器的 ApplicationContext(AnnotationConfigServletWebServerApplicationContext)
要支持内嵌的 WEB 容器的 Spring 容器,有三项是必须配置的
- 内嵌 web 容器工厂
- 创建 DispatcherServlet
- 注册 DispatcherServlet, Spring MVC 的入口
/**
* 内嵌 web 容器配置信息
*/
@Configuration
@ComponentScan
@PropertySource("classpath:application.properties") // 使用配置文件中的参数
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class}) // spring 中获取配置文件中前缀对象注解
public class MyWebConfig {
// 1. 内嵌 web 容器工厂
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory(ServerProperties serverProperties) {
// 获取配置文件中 server.port 的值
return new TomcatServletWebServerFactory(serverProperties.getPort());
}
// 2. 创建 DispatcherServlet
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
// 3. 注册 DispatcherServlet, Spring MVC 的入口
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties) {
DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");
return registrationBean;
}
}
- 启动类
public class DispatcherservletDemo {
private static final Logger log = LoggerFactory.getLogger(DispatcherservletDemo.class);
public static void main(String[] args) {
// 支持内嵌 web 容器的 spring 容器
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(MyWebConfig.class);
}
}
- 启动日志分析
- 发送第一次 request,dispatcherServlet 对象才开始初始化
- 调整 dispatcherServlet 对象初始化时机
- 默认 dispatcherServlet 对象初始化时机是第一次request时,先调整为当 tomcat 容器启动时,初始化 dispatcherServlet 对象;
- 原因:org.springframework.boot.web.servlet.ServletRegistrationBean 中 loadOnStartup 的默认值为 -1;
- 解决:loadOnStartup 值大于 -1 即可;
- 修改 MyWebConfig 中 DispatcherServletRegistrationBean 的 setLoadOnStartup 值;
/**
* 内嵌 web 容器配置信息
*/
@Configuration
@ComponentScan
@PropertySource("classpath:application.properties") // 使用配置文件中的参数
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class}) // spring 中获取配置文件中前缀对象注解
public class MyWebConfig {
......
// 3. 注册 DispatcherServlet, Spring MVC 的入口
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties) {
DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");
// 获取配置文件中 spring.mvc.servlet.load-on-startup 的值(spring.mvc.servlet.load-on-startup=1)
registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
return registrationBean;
}
}
DispatcherServlet 初始化都做了什么
参考源码;org.springframework.web.servlet.DispatcherServlet#onRefresh
@Override
protected void onRefresh(ApplicationContext context) {
// 初始化各个组件
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
// 初始化文件解析器
initMultipartResolver(context);
// 初始化本地化信息,如:那个地区,那个国家
initLocaleResolver(context);
// 用于准备DispatcherServlet处理请求时所使用的ThemeResolver策略组件对象
initThemeResolver(context);
// 初始化路径映射
initHandlerMappings(context);
// 适配不同形式的控制器方法
initHandlerAdapters(context);
// 解析处理器中的异常
initHandlerExceptionResolvers(context);
// 主要用于理请求时所使用的策略
initRequestToViewNameTranslator(context);
// 初始视图处理器
initViewResolvers(context);
// 用于生成FlashMap管理器
initFlashMapManager(context);
}
随便挑一个(initHandlerMappings),简单的看一下实现
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// detectAllHandlerMappings 用来判断是否检测所有的容器
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
// 只检测当前容器
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
// 容器中没有 handlerMappings,则获取默认的
if (this.handlerMappings == null) {
// 默认的 handlerMappings,见下面源码
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
for (HandlerMapping mapping : this.handlerMappings) {
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
// 获取默认配置信息
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
if (defaultStrategies == null) {
try {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
// DEFAULT_STRATEGIES_PATH 默认配置文件中信息
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());
}
}
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Unresolvable class definition for DispatcherServlet's default strategy class [" +
className + "] for interface [" + key + "]", err);
}
}
return strategies;
}
else {
return Collections.emptyList();
}
}
RequestMappingHandlerMapping 的基本用途
RequestMappingHandlerMapping 初始化时,会收集所有 @RequestMapping 以及派生注解(如:@GetMapping) 映射信息,封装为 Map,其中
- key 是 RequestMappingInfo 类型,包括请求路径、请求方法等信息;
- value 是 HandlerMethod 类型,包括控制器方法对象、控制器对象;
- 有了这个 Map,就可以在请求到达时,快速完成映射,找到 HandlerMethod 并与匹配的拦截器一起返回给 DispatcherServlet;
- controller
@Controller
public class MyController {
private static final Logger log = LoggerFactory.getLogger(MyController.class);
@GetMapping("/test1")
public ModelAndView test1() throws Exception {
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(@MyToken String token) {
log.debug("test3({})", token);
return null;
}
@RequestMapping("/test4")
// @ResponseBody
@MyYml
public User test4() {
log.debug("test4");
return new User("张三", 18);
}
public static class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
String str = new Yaml().dump(new User("张三", 18));
System.out.println(str);
}
}
- main 方法
public class DispatcherservletDemo {
private static final Logger log = LoggerFactory.getLogger(DispatcherservletDemo.class);
public static void main(String[] args) throws Exception {
// 支持内嵌 web 容器的 spring 容器
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(MyWebConfig.class);
// 获取 RequestMappingHandlerMapping bean 对象
// 作用 解析 @RequestMapping 以及派生注解,生成路径与控制器方法的映射关系, 在初始化时就生成
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethodsMap = handlerMapping.getHandlerMethods();
log.debug("RequestMappingHandlerMapping 中生成路径与控制器方法的映射关系 ===>");
handlerMethodsMap.forEach((k, v) -> log.debug("K = {} , V = {}", k, v));
// 模拟请求,访问 test1
MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest("GET", "/test1");
// 返回处理器链对象
HandlerExecutionChain chain = handlerMapping.getHandler(mockHttpServletRequest);
log.debug("处理器链对象:{}", chain);
}
}
-
MyWebConfig
如果用 DispatcherServlet 初始化时默认添加的组件, 并不会作为 spring 容器中的 bean,导致获取不到,需要在 MyWebConfig 中将 RequestMappingHandlerMapping 加入到 spring 容器中
// 如果用 DispatcherServlet 初始化时默认添加的组件, 并不会作为 spring 容器中的 bean,导致获取不到
// 1. 将 RequestMappingHandlerMapping 加入到 spring 容器中
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
- 运行日志:其中 interceptors 为拦截器
RequestMappingHandlerAdapter 基本用途
RequestMappingHandlerAdapter 初始化时,会准备 HandlerMethod 调用时需要的各个组件,如:
- HandlerMethodArgumentResolver 解析控制器方法参数
- HandlerMethodReturnValueHandler 处理控制器方法返回值
- MyWebConfig
- 如果用 DispatcherServlet 初始化时默认添加的组件, 并不会作为 spring 容器中的 bean,导致获取不到,需要在 MyWebConfig 中将 RequestMappingHandlerAdapter 加入到 spring 容器中
- 因为 RequestMappingHandlerAdapter 中的 invokeHandlerMethod 是 protected,测试类无法直接调用,通过 extend 修改方法的作用域
// 2. 继续加入 RequestMappingHandlerAdapter, 会替换掉 DispatcherServlet 默认的 4 个 HandlerAdapter
// 因为 RequestMappingHandlerAdapter 中的 invokeHandlerMethod 是 protected,测试类无法直接调用,通过 extend 修改方法的作用域
@Bean
public MyRequestMappingHandlerAdapter requestMappingHandlerAdapter() {
MyRequestMappingHandlerAdapter handlerAdapter = new MyRequestMappingHandlerAdapter();
return handlerAdapter;
}
- RequestMappingHandlerAdapter 获取参数处理器
public class DispatcherservletDemo {
private static final Logger log = LoggerFactory.getLogger(DispatcherservletDemo.class);
public static void main(String[] args) throws Exception {
// 支持内嵌 web 容器的 spring 容器
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(MyWebConfig.class);
// 获取 RequestMappingHandlerMapping bean 对象
// 作用 解析 @RequestMapping 以及派生注解,生成路径与控制器方法的映射关系, 在初始化时就生成
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethodsMap = handlerMapping.getHandlerMethods();
log.debug("RequestMappingHandlerMapping 中生成路径与控制器方法的映射关系 ===>");
handlerMethodsMap.forEach((k, v) -> log.debug("K = {} , V = {}", k, v));
// 模拟请求,访问 test1
// MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest("GET", "/test1");
// 模拟请求,访问 test2
MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest("POST", "/test2");
mockHttpServletRequest.addParameter("name", "王小闹");
MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();
// 返回处理器链对象
HandlerExecutionChain chain = handlerMapping.getHandler(mockHttpServletRequest);
log.debug("处理器链对象:{}", chain);
log.debug("< ---------- 调用控制器方法 ---------- >");
// HandlerAdapter 作用: 调用控制器方法
MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
handlerAdapter.invokeHandlerMethod(mockHttpServletRequest, mockHttpServletResponse, (HandlerMethod)chain.getHandler());
// handlerAdapter 中参数解析器
log.debug("< ---------- handlerAdapter 中参数解析器 ---------- >");
for (HandlerMethodArgumentResolver argumentResolver : Objects.requireNonNull(handlerAdapter.getArgumentResolvers())) {
log.debug("{}", argumentResolver);
}
// handlerAdapter 中响应参数解析器
log.debug("< ---------- handlerAdapter 中参数解析器 ---------- >");
for (HandlerMethodReturnValueHandler returnValueHandler : Objects.requireNonNull(handlerAdapter.getReturnValueHandlers())) {
log.debug("{}", returnValueHandler);
}
}
}
- 运行日志
日志:DispatcherservletDemo - RequestMappingHandlerMapping 中生成路径与控制器方法的映射关系 ===>
日志:DispatcherservletDemo - K = {POST [/test2]} , V = com.exam.springmvc.dispatcherservlet.MyController#test2(String)
日志:DispatcherservletDemo - K = {GET [/test1]} , V = com.exam.springmvc.dispatcherservlet.MyController#test1()
日志:DispatcherservletDemo - K = { [/test4]} , V = com.exam.springmvc.dispatcherservlet.MyController#test4()
日志:DispatcherservletDemo - K = {PUT [/test3]} , V = com.exam.springmvc.dispatcherservlet.MyController#test3(String)
21:22:55.775 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.exam.springmvc.dispatcherservlet.MyController#test2(String)
日志:DispatcherservletDemo - 处理器链对象:HandlerExecutionChain with [com.exam.springmvc.dispatcherservlet.MyController#test2(String)] and 0 interceptors
日志:DispatcherservletDemo - < ---------- 调用控制器方法 ---------- >
21:22:55.783 [main] DEBUG com.exam.springmvc.dispatcherservlet.MyController - test2(王小闹)
日志:DispatcherservletDemo - < ---------- handlerAdapter 中参数解析器 ---------- >
日志:DispatcherservletDemo - org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@3af17be2
日志:DispatcherservletDemo - org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@f9879ac
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@37f21974
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver@5f4d427e
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver@6e521c1e
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver@224b4d61
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@5d5d9e5
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@303e3593
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@4ef27d66
日志:DispatcherservletDemo - org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@362a019c
日志:DispatcherservletDemo - org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@1d9bec4d
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@5c48c0c0
日志:DispatcherservletDemo - org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@10c8f62
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver@674c583e
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver@25f7391e
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@3f23a3a0
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver@5ab14cb9
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@5fb97279
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver@439a8f59
日志:DispatcherservletDemo - org.springframework.web.method.annotation.ModelMethodProcessor@61861a29
日志:DispatcherservletDemo - org.springframework.web.method.annotation.MapMethodProcessor@31024624
日志:DispatcherservletDemo - org.springframework.web.method.annotation.ErrorsMethodArgumentResolver@25bcd0c7
日志:DispatcherservletDemo - org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver@32cb636e
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.UriComponentsBuilderMethodArgumentResolver@63cd604c
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.PrincipalMethodArgumentResolver@40dd3977
日志:DispatcherservletDemo - org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@3a4e343
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@6a1d204a
日志:DispatcherservletDemo - < ---------- handlerAdapter 中参数解析器 ---------- >
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler@62dae245
日志:DispatcherservletDemo - org.springframework.web.method.annotation.ModelMethodProcessor@4b6579e8
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler@6fff253c
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler@6c6357f9
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler@591e58fa
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@3954d008
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler@2f94c4db
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler@593e824f
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler@72ccd81a
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler@6d8792db
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@64bc21ac
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@493dfb8e
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler@5d25e6bb
日志:DispatcherservletDemo - org.springframework.web.method.annotation.MapMethodProcessor@ce5a68e
日志:DispatcherservletDemo - org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@9d157ff
自定义参数与返回值处理器
- MyWebConfig
// 2. 继续加入 RequestMappingHandlerAdapter, 会替换掉 DispatcherServlet 默认的 4 个 HandlerAdapter
// 因为 RequestMappingHandlerAdapter 中的 invokeHandlerMethod 是 protected,测试类无法直接调用,通过 extend 修改方法的作用域
@Bean
public MyRequestMappingHandlerAdapter requestMappingHandlerAdapter() {
MyRequestMappingHandlerAdapter myHandlerAdapter = new MyRequestMappingHandlerAdapter();
// 参数解析器
List<HandlerMethodArgumentResolver> argumentResolverList = new ArrayList<>();
argumentResolverList.add(new MyTokenArgumentResolver());
myHandlerAdapter.setArgumentResolvers(argumentResolverList);
// 响应参数解析器
List<HandlerMethodReturnValueHandler> returnValueHandlerList = new ArrayList<>();
returnValueHandlerList.add(new MyYmlReturnValueHandler());
myHandlerAdapter.setCustomReturnValueHandlers(returnValueHandlerList);
return myHandlerAdapter;
}
- 自定义 参数解析器:MyTokenArgumentResolver
/**
* 自定义 RequestMappingHandlerAdapter 参数解析器
*/
public class MyTokenArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 是否支持某个参数,返回 true 时,resolveArgument 才执行
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
MyToken myToken = parameter.getParameterAnnotation(MyToken.class);
return myToken != null;
}
/**
* 解析参数
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
return webRequest.getHeader("token");
}
}
- 自定义响应参数解析器:MyYmlReturnValueHandler
/**
* 自定义响应参数解析器
*/
public class MyYmlReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
MyYml myYml = returnType.getMethodAnnotation(MyYml.class);
return myYml != null;
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
// 1. 转换返回结果为 yaml 字符串
String str = new Yaml().dump(returnValue);
// 2. 将 yaml 字符串写入响应
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
assert response != null;
response.setContentType("text/plain;charset=utf-8");
response.getWriter().print(str);
// 3. 设置请求已经处理完毕
mavContainer.setRequestHandled(true);
}
}
- main
public class DispatcherservletDemo {
private static final Logger log = LoggerFactory.getLogger(DispatcherservletDemo.class);
public static void main(String[] args) throws Exception {
// 支持内嵌 web 容器的 spring 容器
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(MyWebConfig.class);
// 获取 RequestMappingHandlerMapping bean 对象
// 作用 解析 @RequestMapping 以及派生注解,生成路径与控制器方法的映射关系, 在初始化时就生成
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethodsMap = handlerMapping.getHandlerMethods();
log.debug("RequestMappingHandlerMapping 中生成路径与控制器方法的映射关系 ===>");
handlerMethodsMap.forEach((k, v) -> log.debug("K = {} , V = {}", k, v));
// 模拟请求,访问 test1
// MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest("GET", "/test1");
// 模拟请求,访问 test2
// MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest("POST", "/test2");
// mockHttpServletRequest.addParameter("name", "王小闹");
// 模拟请求,访问 test3
// MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest("PUT", "/test3");
// mockHttpServletRequest.addHeader("token", "424bhk2424232334");
// 模拟请求,访问 test3
MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest("PUT", "/test4");
MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();
// 返回处理器链对象
HandlerExecutionChain chain = handlerMapping.getHandler(mockHttpServletRequest);
log.debug("处理器链对象:{}", chain);
log.debug("< ---------- 调用控制器方法 ---------- >");
// HandlerAdapter 作用: 调用控制器方法
MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
handlerAdapter.invokeHandlerMethod(mockHttpServletRequest, mockHttpServletResponse, (HandlerMethod)chain.getHandler());
// 检查响应
byte[] content = mockHttpServletResponse.getContentAsByteArray();
log.debug("自定义响应参数解析器:{}", new String(content, StandardCharsets.UTF_8));
/*// handlerAdapter 中参数解析器
log.debug("< ---------- handlerAdapter 中参数解析器 ---------- >");
for (HandlerMethodArgumentResolver argumentResolver : Objects.requireNonNull(handlerAdapter.getArgumentResolvers())) {
log.debug("{}", argumentResolver);
}
// handlerAdapter 中响应参数解析器
log.debug("< ---------- handlerAdapter 中参数解析器 ---------- >");
for (HandlerMethodReturnValueHandler returnValueHandler : Objects.requireNonNull(handlerAdapter.getReturnValueHandlers())) {
log.debug("{}", returnValueHandler);
}*/
}
}