webFluxラーニング(II)

webFlux

webFluxはspring5は、網状またはServlet3.1上で実行する、非ブロッキングと提案されています

MVCとwebFluxそれは何を問題ではありませんか?

1.ブロッキングとノンブロッキング

webfluxは非ブロックモードはスレッドでより多くの要求を処理できることです

MVCはリクエストがコンテナのスレッドの我々の開発モデルに対応する伝統的なブロックであります 

2.動作環境

MVCは、上記のサーブレットコンテナを実行する必要がありサーブレットAPIに基づいています

webflux式は応答ストリームに基づいて、またはそれは網状の上にサーブレットを実行することができます

3.データの側面

リレーショナル・データは一時的に利用できないwebfluxです

優位

1.拡張サポート並行性の高い水平/垂直方向の拡大は、我々は垂直方向に拡張webflux使用することができます。

サーブレット

サーブレットを作成するためのアイデア  https://blog.csdn.net/a376298333/article/details/79121548を

なぜ非同期サーブレットを使うのか?

@WebServlet(urlPatterns = { "/AsyncServlet" },asyncSupported = true)
public class AyncServlet extends HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        long start = System.currentTimeMillis();
        //1.开启异步
        AsyncContext asyncContext = request.startAsync();
        //2.执行耗时操作
        CompletableFuture.runAsync(()->{
            something(asyncContext,asyncContext.getRequest(),asyncContext.getResponse());
        });


        System.out.println("aynctime use: "+ (System.currentTimeMillis()-start));
    }

    private void something(AsyncContext asyncContext, ServletRequest request, ServletResponse response)  {
        //模拟耗时操作
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {
            response.getWriter().append("aync done");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //业务代码处理完.我们要通知他
        asyncContext.complete();
    }
}

aynctime use: 11

这是一个异步的servlet http://localhost:8080/AsyncServlet 访问在前台来看还是5秒钟

但是后台的时间是11ms 不会阻塞tomcat线程 可以把一些耗时的操作放在独立线程池里,我们的serlet线程就可以处理下一个线程达到比较高的吞吐量

同步servlet阻塞了什么?

/**
 * @Created by xiaodao
 */
@WebServlet("/SyncServlet")
public class SyncServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        long start = System.currentTimeMillis();
        System.out.println(start);
        something(request,response)
        ;

        System.out.println("time use: "+ (System.currentTimeMillis()-start));
    }

    private void something(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //模拟耗时操作
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        response.getWriter().append("done");
    }
}

time use :5001

在浏览器中访问可以看到我们返回需要5m中.这时候我们就知道

同步的servlet阻塞了tomcat容器的servlet线程,

当我们的网络请求->tomcat容器->为每一个请求启动一个线程去处理->线程里找一个servlet线程来处理

异步servlet怎么工作的?

1.我们开启异步支持

2.把页面代码放到独立的线程池执行

3.调用异步上下文的comlate方法通知他结束

webFlux 入门

什么是reactor编程呢?就是jdk8 stream + jdk11 reactive stream 

mono: 0-1个元素

flux:0-N个元素

我们来一个示例程序看下:

/**
 * @Created by xiaodao
 */
public class Main {

    public static void main(String[] args) {
        String[] arr = {"1","2","3","4"};
        Subscriber<Integer> subscriber = new Subscriber<Integer>() {
            private Subscription subscription;
            @Override
            public void onSubscribe(Subscription subscription) {
                this.subscription =subscription;
                this.subscription.request(1);
            }

            @Override
            public void onNext(Integer integer) {
                System.out.println(integer);
                this.subscription.request(1);
            }

            @Override
            public void onError(Throwable throwable) {

            }

            @Override
            public void onComplete() {

            }
        };
        //jdk8 stream 这个时候并没有执行
        Flux.fromArray(arr).map(s->Integer.parseInt(s))
                .subscribe(subscriber);//jdk9 的 reactive stream
    }
}

jdk8 的流可以看做是一个发布者

jdk9的subscribe可以看做是一个订阅者.

来看下webflux是如何执行的?

@RestController
@Slf4j
public class TestController {


    @GetMapping("/test1")
    public String test1(){
        log.info("start");
        String str  = createStr();
        log.info("end");
        return  str;
    }

    @GetMapping("/test2")
    public Mono<String> test2(){
        log.info("mono start");
        Mono<String> stringMono = Mono.fromSupplier(() -> createStr());
        log.info("mono end ");
        return stringMono;
    }


    public String createStr(){
        try {

            TimeUnit.SECONDS.sleep(5);


        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello web flux ";
    }
}

上面的代码是一个简单的操作我们模拟业务需求让代码耗时5秒钟的时间

在浏览器中分别访问test1 test2 在浏览器中都是等待5秒钟,这点都都一样,对于浏览器来说不存在同步和异步之说,阻塞和非阻塞,同步与异步只存在于服务端

接下来我们来看来在spring中是如何执行的.

 

我们可以看到当我们访问test1 的时候test1 controller方法就占用了5秒钟的时间

第二种模式,controller是基本没有耗时的,我们新模式中返回的mono实际上是返回了一个流,当调用subscibe()方法的时候才会执行 

flux

   @GetMapping(value = "/test3",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> test3(){
        log.info("mono start");

        Flux<String> stringMono = Flux.fromStream(IntStream.range(1,5).mapToObj(i->{
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "flux data "+i+"/n";
        }));
        return stringMono;
    }

 

おすすめ

転載: www.cnblogs.com/bj-xiaodao/p/11046716.html