0.前记
根据之前的文章可知HandlerAdapter 主要的是RequestMappingHandlerAdapter 的效果
本章解释一下RequestMappingHandlerAdapte r的具体使用情况
1.RequestMappingHandlerAdapter 的初始化
根据前文可知在DispatcherServlet 初始化的时候会初始化HandlerAdapter
这里默认会初始化RequestMappingHandlerAdapter, 而RequestMappingHandlerAdapter 实现了InitializingBean 接口
会实现afterPropertiesSet() 方法
- 初始化@ControllerAdvice
- 初始化参数解析器 argumentResolvers
- 初始化绑定参数解析器 initBinderArgumentResolvers
- 初始化返回值解析器 returnValueHandlers
下面列举的都是参数解析器 以上就添加了参数解析器和返回值解析器
2.参数解析器解析
WebConfig.java
@Configuration
@ComponentScan
@PropertySource("classpath:application.properties")
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class})
public class WebConfig {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory(ServerProperties serverProperties){
return new TomcatServletWebServerFactory(serverProperties.getPort());
}
@Bean
public DispatcherServlet dispatcherServlet(){
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(WebMvcProperties webMvcProperties){
DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet(), "/");
registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
return registrationBean;
}
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(){
return new RequestMappingHandlerMapping();
}
@Bean
public MyRequestMappingHandlerAdapter requestMappingHandlerAdapter(){
return new MyRequestMappingHandlerAdapter();
}
}
MyRequestMappingHandlerAdapter.java
public class MyRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
@Override
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
return super.invokeHandlerMethod(request, response, handlerMethod);
}
}
Controller1.java
@RestController
public class Controller1 {
@GetMapping("/test1")
public String test1(){
System.out.println("1");
return "1";
}
}
A20.java
public class A20 {
public static void main(String[] args) throws Exception {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = handlerMapping.getHandlerMethods();
map.forEach((k, v) -> {
System.out.println(k + " = " + v);
});
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test1");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain chain = handlerMapping.getHandler(request);
System.out.println(chain);
MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
handlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());
System.out.println(">>>>>>>> 参数解析器");
for (HandlerMethodArgumentResolver argumentResolver : handlerAdapter.getArgumentResolvers()) {
System.out.println(argumentResolver);
}
System.out.println(">>>>>>>> 返回值解析器");
for (HandlerMethodReturnValueHandler returnValueHandler : handlerAdapter.getReturnValueHandlers()) {
System.out.println(returnValueHandler);
}
}
}
获取到参数解析器和返回值解析器
模拟发生get请求
MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
handlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());
3.自定义参数解析器
这里自定义了一个@Token, 用于解析参数的带有头信息的token值
- Token .java
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
}
- TokenArgumentResolver.java
public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
Token token = parameter.getParameterAnnotation(Token.class);
return token != null;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return webRequest.getHeader("token");
}
}
- WebConfig.java
- Controller1.java
- A20.java
- 这里利用了模拟PUT请求/test2的, 并加入了token
4.参数解析器的执行过程
先拿到方法的参数, 然后解析, 最后通过反射执行
所以说最后是通过反射去执行方法的。
5.参数解析过程
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
- 先找到提供的参数
findProvidedArgument - 解析器进行解析
resolveArgument , 之前先判断解析器是否可以解析 supportsParameter
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
这里先看缓存有无, 第一次的话缓存肯定无, 那么就加入到缓存。这里为优化部分
下面的为实现了supportsParameter 方法的参数解析器
|