24.SpringBoot中异步使用的一些总结

前言

后端的异步可能不像前端用异步那样频繁,前端渲染页面可能异步处理更常见,后端异步可能考虑的主要是为了增加服务器端的吞吐量。当然有些时候也能提升一些性能。本文主要是总结下现阶段我是使用的比较好的异步处理的方式,基于springboot的使用。
参考:
https://www.cnblogs.com/baixianlong/p/10661591.html

一、不常用的异步请求的方式介绍

1.1 HttpServletRequest方式实现异步请求:

其原理就是多线程实现的异步,当然此异步也是没有不适合接口返回值的,参考代码为:

   AsyncContext asyncContext = request.startAsync();
        //设置监听器:可设置其开始、完成、异常、超时等事件的回调处理
        asyncContext.addListener(new AsyncListener()

代码没粘完,主要就是实现上面接口的实现。

1.2 接口返回的参数包裹一层callable,设置线程池和超时处理:

代码:

@RequestMapping("/opt/test3")
    public Callable<String> test3(){
        System.out.println("外部线程:" + Thread.currentThread().getName());

        return new Callable<String>() {

            @Override
            public String call() throws Exception {
                Thread.sleep(10000);
                System.out.println("内部线程:" + Thread.currentThread().getName());
                return "callable!";
            }
        };

    }

线程池配置:

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer 


  @Resource
   private ThreadPoolTaskExecutor myThreadPoolTaskExecutor;

    @Override
    public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
        //处理 callable超时
        configurer.setDefaultTimeout(60*1000);
        configurer.setTaskExecutor(myThreadPoolTaskExecutor);
        configurer.registerCallableInterceptors(timeoutCallableProcessingInterceptor());
    }

    @Bean
    public TimeoutCallableProcessingInterceptor timeoutCallableProcessingInterceptor() {
        return new TimeoutCallableProcessingInterceptor();
    }

1.3 跟方式2差不多,就是WebAsyncTask设置一个超时回调,实现超时处理:

代码:

 @RequestMapping(value = "/email/webAsyncReq", method = GET)
    @ResponseBody
    public WebAsyncTask<String> webAsyncReq () {
        System.out.println("外部线程:" + Thread.currentThread().getName());
        Callable<String> result = () -> {
            System.out.println("内部线程开始:" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (Exception e) {
                // TODO: handle exception
            }
            logger.info("副线程返回");
            System.out.println("内部线程返回:" + Thread.currentThread().getName());
            return "success";
        };
        WebAsyncTask<String> wat = new WebAsyncTask<String>(3000L, result);
        wat.onTimeout(new Callable<String>() {

            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "超时";
            }
        });
        return wat;
    }

1.4 通过DeferredResult实现:

@RequestMapping(value = "/email/deferredResultReq", method = GET)
    @ResponseBody
    public DeferredResult<String> deferredResultReq () {
        System.out.println("外部线程:" + Thread.currentThread().getName());
        //设置超时时间
        DeferredResult<String> result = new DeferredResult<String>(60*1000L);
        //处理超时事件 采用委托机制
        result.onTimeout(new Runnable() {

            @Override
            public void run() {
                System.out.println("DeferredResult超时");
                result.setResult("超时了!");
            }
        });
        result.onCompletion(new Runnable() {

            @Override
            public void run() {
                //完成后
                System.out.println("调用完成");
            }
        });
        myThreadPoolTaskExecutor.execute(new Runnable() {

            @Override
            public void run() {
                //处理业务逻辑
                System.out.println("内部线程:" + Thread.currentThread().getName());
                //返回结果
                result.setResult("DeferredResult!!");
            }
        });
       return result;
    }

二、SpringBoot中异步注解调用的使用:

总结的使用就是两步:

1.启动类或者配置类启动异步使用:
@EnableAsync使异步调用

2.设置方法异步注解:
@Async

其中比较重要的总结是@Async(“threadPoolTaskExecutor”) 传递线程池参数的时候把自定义的线程池进行传递设置,而不是使用的是默认的SimpleAsyncTaskExecutor线程池。
代码实现:

  @RequestMapping("/opt/test")
    public Object findObj(HttpServletRequest request) {
        List<UserLocal> userLocalList=new ArrayList<>();
         userLocalList = userService.selectAll();
        return userLocalList;
    }
      @Async("threadPoolTaskExecutor")
    public List<UserLocal> selectAll() {
          List<UserLocal> userLocalList = userLocalMapper.selectAll();
        return userLocalList;
    }

异步请求是用来解决并发请求对服务器造成的压力,从而提高队请求的吞吐量,而异步调用是用来做一些非主线流程而不需要实时计算和相应的任务,比如同步日志到日志分析中心等。

二、RxJava实现异步:

2.1 代码实现:

使用的依赖:

<dependency>
            <groupId>io.reactivex.rxjava2</groupId>
            <artifactId>rxjava</artifactId>
            <version>2.2.10</version>
        </dependency>

控制器代码实现:

 @RequestMapping("/findObserver")
    public Object findObserver() {
        User user = new User();
        user.setName("11");
        user.setAge(11);
        Observable<List<UserLocal>> userInfoModelObservable = dataHandleService.findData(user);
        Object apiReturn = toApiReturn(userInfoModelObservable);
        return apiReturn;
    }
    private DeferredResult toApiReturn(Observable<List<UserLocal>> details) {
        DeferredResult<List<UserLocal>> result = new DeferredResult();
        List<UserLocal> userLocalList=new ArrayList<>();

        details.subscribe(new Observer<List<UserLocal>>() {
            @Override
            public void onSubscribe(@NonNull Disposable disposable) {

            }

            @Override
            public void onNext(@NonNull List<UserLocal> userLocal) {
//                userLocalList.add(userLocal);
                result.setResult(userLocal);
            }

            @Override
            public void onError(@NonNull Throwable throwable) {
                log.error("事件流处理过程中,发生异常,toApiReturn");
            }

            @Override
            public void onComplete() {

            }
        });
        return result;
    }

Service代码实现:

 public Observable<List<UserLocal>> findData(User user) {
        return Observable.zip(observableService.find1(1), observableService.find1(2), observableService.find1(3), observableService.find1(4), this::build);
    }
    
      public Observable<UserLocal> find1(int id) {
        System.out.println(id);
        ObservableOnSubscribe<UserLocal> source = new ObservableOnSubscribe<UserLocal>() {
            @Override
            public void subscribe(ObservableEmitter<UserLocal> emitter) throws Exception {

                long startTime = System.currentTimeMillis();
                UserLocal itemResponseDTO = userLocalMapper.selectByPrimaryKey(id);

                emitter.onNext(itemResponseDTO);
                emitter.onComplete();

                log.info("Response time of getKnowledge : {} milliseconds", System.currentTimeMillis() - startTime);
            }
        };

        return Observable.<UserLocal>create(source)
                .doOnNext(c -> log.info("Item details were getKnowledge successfully."))
              // .onErrorReturn(itemServiceApiErrorHandler)
                .subscribeOn(Schedulers.io());
    }

2.2 理论介绍:

RxJava 一个词概括就是:异步。特点就是:简洁。

实现的原理:RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。

四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。

与传统的观察模式对比:RxJava 的事件回调方法除了普通事件 onNext() (相当于 onClick() / onEvent())之外,还定义了两个特殊的事件:onCompleted() 和 onError()。

onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。

onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。

在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。

2.3 实现流程:

1)创建 Observer->2) 创建 Observable->3) Subscribe (订阅)

参考:https://www.cnblogs.com/xuecanmeng/p/6888351.html

结尾:

上面就是异步的使用总结,如果你在工作当中遇到异步的使用场景,可以以上面的作为参考,应该能满足绝大部分异步使用场景,换用点赞、留言、转发、赞赏。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值