SpringMVC自定义处理返回值demo和异步处理模式DeferredResult demo

发布时间 2023-10-20 21:13:45作者: 王景迁

搭建自定义返回值处理器demo

新建springboot项目

修改pom.xml

<!-- 新增依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.54</version>
</dependency>

MyResponseBody注解

package com.example.handlermethodreturnvaluehandlerdemo;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyResponseBody {
}

UserController类

package com.example.handlermethodreturnvaluehandlerdemo;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @MyResponseBody
    @GetMapping("/user")
    public int getUser() {
        return 1;
    }
}

MyReturnValueHandler类

package com.example.handlermethodreturnvaluehandlerdemo;

import com.alibaba.fastjson.JSON;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletResponse;

public class MyReturnValueHandler implements HandlerMethodReturnValueHandler {

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return returnType.hasMethodAnnotation(MyResponseBody.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        mavContainer.setRequestHandled(true);
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        response.getWriter().write(JSON.toJSONString(2));
    }
}

MyReturnValueHandlerRegister类

package com.example.handlermethodreturnvaluehandlerdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class MyReturnValueHandlerRegister implements WebMvcConfigurer {
    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @PostConstruct
    public void init(){
        // 注册PropertiesHandlerMethodReturnValueHandler
        List<HandlerMethodReturnValueHandler> handlers = requestMappingHandlerAdapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<>(handlers.size() + 1) ;
        newHandlers.addAll(handlers);
        newHandlers.add(new MyReturnValueHandler());
        // 重置Handler对象集合
        requestMappingHandlerAdapter.setReturnValueHandlers(newHandlers);
    }
}

返回2

自定义返回值处理器执行流程

HandlerMethodReturnValueHandler接口处理controller返回值

public interface HandlerMethodReturnValueHandler {
	// 是否支持返回值类型
	boolean supportsReturnType(MethodParameter returnType);
	// 处理返回值
	void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}

debug接口http://127.0.0.1:8080/user

HandlerMethodReturnValueHandler有15种,包括自定义返回值处理器。
每个请求在HandlerMethodReturnValueHandler列表中从前向后遍历,选择一个HandlerMethodReturnValueHandler来处理。
选择过程
第1步:ServletInvocableHandlerMethod类中invokeAndHandle方法

第2步:HandlerMethodReturnValueHandlerComposite类中handleReturnValue方法

搭建异步处理模式DeferredResult demo

package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

@RestController
@RequestMapping("/deferredResult")
public class DeferredResultTestController {
    private DeferredResult<String> deferredResult = new DeferredResult<>();

    @RequestMapping("/hold")
    public DeferredResult<String> hold() {
        return deferredResult;
    }

    @RequestMapping("/release")
    public void release() {
        deferredResult.setResult("");
    }
}

调用hold接口后一直卡住,直到调用release接口或者http请求超时。

DeferredResult执行流程

1. 第1次收到请求,保存返回的DeferredResult对象,用于后续访问。
2. tomcat请求线程被回收到线程池中。 
3. tomcat线程每隔1秒遍历waitingProcessors里面的processor,确认是否过期。如果过期了,就把超时默认值写入DeferredResult对象;否则,业务线程把结果写入之前的DeferredResult对象。
4. 内部自动发起第2次请求,再次调用DispatcherServlet,由ResponseBody返回值处理器返回DeferredResult对象中的数据。

参考资料

https://blog.csdn.net/agonie201218/article/details/123954205