springboot custom parameter processor and return value processor

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;
    }
}

Tags: Java Spring Boot Back-end

Posted on Tue, 09 Nov 2021 14:47:14 -0500 by upit