Argument resolvers and returnvaluehandlers
When we call the controller layer component, springboot actually uses the proxy mode to call. springmvc defines a dispatcher servlet to implement the HttpServlet method. The request is processed through the doservice() method of the dispatcher servlet. In the doservice method, Springboot first generates the mapperHandler object containing the necessary information for processing the request according to the request object of the request, then generates the HandlerAdapter object for actually processing the request according to the mapperHandler object, and calls the handle method of the HandlerAdapter to process the request. Before and after executing the processing method code actually defined by us, HandlerAdapter will call some agent enhancements, including selecting the appropriate parameter processor according to the definition of our method to encapsulate the parameters in the request into objects. After obtaining the objects, we will use the processed parameters to execute the controller layer processing logic defined by us through reflection. Similarly, after executing the actual method, After selecting the appropriate return value, the processor really processes the return.
The WebMvcConfigurationSupport configuration class configures various default processors of springboot
Custom processor
For * * * Custom parameter processors, springboot provides a HandlerMethodArgumentResolver interface***
The custom return parameter processor springboot provides a HandlerMethodReturnValueHandler interface.
By implementing the above two interfaces, we can implement our own custom processor.
springboot also has an abstract class called AbstractMessageConverterMethodProcessor. This abstract class implements the above two parameter processor interfaces and return parameter processor interfaces. We can directly inherit the AbstractMessageConverterMethodProcessor abstract class and rewrite relevant methods to implement parameter processor and return value processor at the same time.
- It should be noted that Spring has many default parameter processors. When calling at the bottom of springboot, all processors are stored in a list set and called with a for loop. Whoever is cycled to meet the conditions will call. The method to remove the built-in method processor has not been found yet. It is best to define an annotation for identification, So as to be 100% effective.
- Let's implement a custom processor.
Customize an annotation for identification:
@Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnnocation { }
Customize a method processor
@Component public class MyProcesser extends AbstractMessageConverterMethodProcessor { protected MyProcesser(List<HttpMessageConverter<?>> converters) { super(converters); } @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(MyAnnocation.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Bean1 bean1 = new Bean1(); bean1.setName("hello world"); return bean1; } //If the return is a Bean1 type, processing is supported @Override public boolean supportsReturnType(MethodParameter returnType) { return returnType.getMethod().getReturnType().equals(Bean1.class); } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { //Here is an excerpt from the default RequestResponseBodyMethodProcessor of springboot. The processor directly returns the json object. mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); System.out.println("my handleReturnValue"); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); } }
Add this processor to the container
@Configuration public class WebConfigure implements WebMvcConfigurer { private final MyProcesser myProcesser; public WebConfigure(MyProcesser myProcesser) { this.myProcesser = myProcesser; } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(myProcesser); } @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) { handlers.add(myProcesser); } }
Test class
//Note: do not directly use the RestController annotation here. In that case, it is equivalent to adding @ ResponseBody before the method. When traversing the processor, the processing of @ ResponseBody is processed by default //The requestresponseprocessor order may be ahead of our custom processor, so we can't call our custom processor. @Controller public class TestController { @GetMapping("/test") public Bean1 test(@MyAnnocation Bean1 bean) { return bean; } }