异步处理REST服务

版权声明:士,不可以不弘毅,任重而道远 https://blog.csdn.net/superbeyone/article/details/84558190


异步处理REST服务

  • 1. 同步处理

在这里插入图片描述
如Tomcat这样的中间件,所能够接受的线程数量是有限的,当线程满负荷之后,后续请求无法得到处理。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Project: tdt-security
 * @ClassName: AsyncController
 * @Description: 异步处理
 * @Author: Mr.superbeyone
 * @Create: 2018-11-27 12:15
 **/
@RestController
public class AsyncController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/order")
    public String order() throws InterruptedException {
        logger.info("主线程开始");

        Thread.sleep(1000);
        logger.info("主线程返回");
        return "success";
    }
}

执行结果:
在这里插入图片描述

  • 2. 异步处理

在这里插入图片描述

当Http请求进入后,Tomcat中间件的主线程会调用副线程来执行业务逻辑,当副线程的业务逻辑处理完成后,由主线程返回结果。在副线程整个处理业务逻辑的过程中,主线程是可以空闲出来处理其他请求。异步处理方式可以大大提高服务器的吞吐量

3. 使用Runnable异步处理REST服务

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Callable;

/**
 * @Project: tdt-security
 * @ClassName: AsyncController
 * @Description: 异步处理
 * @Author: Mr.superbeyone
 * @Create: 2018-11-27 12:15
 **/
@RestController
public class AsyncController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/order")
    public Callable<String> order() throws Exception {
        logger.info("主线程开始");

        Callable<String> result = () -> {
            logger.info("副线程开始");
            Thread.sleep(1000);
            logger.info("副线程返回");
            return "success";
        };
        logger.info("主线程返回");
        return result;
    }
}

执行结果:
在这里插入图片描述

4. 使用DeferredResult异步处理REST服务

在这里插入图片描述

  • Controller
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

/**
 * @Project: tdt-security
 * @ClassName: AsyncController
 * @Description: 异步处理
 * @Author: Mr.superbeyone
 * @Create: 2018-11-27 12:15
 **/
@RestController
public class AsyncController {

    @Autowired
    MockQueue mockQueue;

    @Autowired
    DeferredResultHolder deferredResultHolder;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/order")
    public DeferredResult<String> order() {
        logger.info("主线程开始");

        //随机生成8位数字作为订单号
        String orderNumber = RandomStringUtils.randomNumeric(8);

        mockQueue.setPlaceOrder(orderNumber);
        DeferredResult<String> result = new DeferredResult<>();

        deferredResultHolder.getMap().put(orderNumber, result);

        logger.info("主线程返回");
        return result;
    }
}
  • 模拟消息对列
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @Project: tdt-security
 * @ClassName: MockQueue
 * @Description: 模拟消息队列
 * @Author: Mr.superbeyone
 * @Create: 2018-11-27 13:39
 **/
@Component
public class MockQueue {
    private String placeOrder;
    private String completeOrder;

    private Logger logger = LoggerFactory.getLogger(getClass());

    public String getPlaceOrder() {
        return placeOrder;
    }

    public void setPlaceOrder(String placeOrder) {

        new Thread(() -> {
            logger.info("接到下单请求:\t" + placeOrder);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.completeOrder = placeOrder;
            logger.info("下单请求处理完毕:\t" + placeOrder);
        }).start();

    }

    public String getCompleteOrder() {
        return completeOrder;
    }

    public void setCompleteOrder(String completeOrder) {
        this.completeOrder = completeOrder;
    }
}
  • 传递DeferredResult结果对象
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.HashMap;
import java.util.Map;

/**
 * @Project: tdt-security
 * @ClassName: DeferredResultHolder
 * @Description: 传递DeferredResult结果对象
 * @Author: Mr.superbeyone
 * @Create: 2018-11-27 13:43
 **/
@Component
public class DeferredResultHolder {

    private Map<String, DeferredResult<String>> map = new HashMap<>();

    public Map<String, DeferredResult<String>> getMap() {
        return map;
    }

    public void setMap(Map<String, DeferredResult<String>> map) {
        this.map = map;
    }
}
  • 队列监听器
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;


/**
 * @Project: tdt-security
 * @ClassName: QueueListener
 * @Description: 队列监听器
 * @Author: Mr.superbeyone
 * @Create: 2018-11-27 14:19
 **/
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    MockQueue mockQueue;

    @Autowired
    DeferredResultHolder deferredResultHolder;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        new Thread(() -> {
            while (true) {
                if (StringUtils.isNotBlank(mockQueue.getCompleteOrder())) {
                    String orderNumber = mockQueue.getCompleteOrder();
                    logger.info("返回订单处理结果:\t" + orderNumber);
                    deferredResultHolder.getMap().get(orderNumber).setResult("place order success");

                    mockQueue.setCompleteOrder(null);

                } else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

访问请求:
在这里插入图片描述
执行结果:
在这里插入图片描述
该示例中一共有三个线程参与到整个执行过程,与Callable相比,是实现多线程业务解耦的。

5. 异步处理配置

import com.tdt.security.filter.TimeFilter;
import com.tdt.security.interceptor.TimeInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.ArrayList;

/**
 * @Project: tdt-security
 * @ClassName: WebConfig
 * @Author: Mr.superbeyone
 * @Time: 2018-11-25 23:36
 * @Description: 自定义配置类
 **/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    	 //配置Callable Interceptor
        configurer.registerCallableInterceptors();
        //配置DeferredResult Interceptor
        configurer.registerDeferredResultInterceptors();
        //设置超时时间
        configurer.setDefaultTimeout(8000);
    }
}

github 项目源码地址

猜你喜欢

转载自blog.csdn.net/superbeyone/article/details/84558190
今日推荐