WebFlux的搭建

 1、Spring WebFlux简介


  (1)什么是webflux
  Spring WebFlux是Spring Framework 5.0中引入的新的反应式Web框架。它的作用与Spring Mvc类似。它不需要Servlet API,完全异步和非阻塞,并通过Reactor项目实现Reactive Streams规范。并且可以在诸如Netty,Undertow和Servlet 3.1+容器的服务器上运行。
  (2)webflux的性能
  请求的耗时不会有很大的改善,但是仅需少量的固定线程和较少的内存即可实现扩展。就是说与springmvc相比较,webflux的请求和响应的速度并没有明显的改善,但是webflux更节约内存。

  (3)如何选择Spring Mvc和Spring WebFlux
  当应用依赖大量阻塞式持久化API和网络API,建议使用Spring Mvc(阻塞式api结合webflux使用,性能不会有大的提升)。
已经使用了非阻塞技术栈(例如持久层框架使用ReactiveMongoDB等响应式框架),建议使用Spring WebFlux。

 2、Spring WebFlux的特点


  特性一 异步非阻塞
  众所周知,SpringMVC是同步阻塞的IO模型,资源浪费相对来说比较严重,当我们在处理一个比较耗时的任务时,例如:上传一个比较大的文件,首先,服务器的线程一直在等待接收文件,在这期间它就像个傻子一样等在那儿(放学别走),什么都干不了,好不容易等到文件来了并且接收完毕,我们又要将文件写入磁盘,在这写入的过程中,这根线程又再次懵bi了,又要等到文件写完才能去干其它的事情。这一前一后的等待,不浪费资源么?
  没错,Spring WebFlux就是来解决这问题的,Spring WebFlux可以做到异步非阻塞。还是上面那上传文件的例子,Spring WebFlux是这样做的:线程发现文件还没准备好,就先去做其它事情,当文件准备好之后,通知这根线程来处理,当接收完毕写入磁盘的时候(根据具体情况选择是否做异步非阻塞),写入完毕后通知这根线程再来处理(异步非阻塞情况下)。这个用脚趾头都能看出相对SpringMVC而言,可以节省系统资源。

  特性二 响应式(reactive)函数编程
  如果你觉得java8的lambda写起来很爽,那么,你会再次喜欢上Spring WebFlux,因为它支持函数式编程,得益于对于reactive-stream的支持(通过reactor框架来实现的),喜欢java8 stream的又有福了。为什么要函数式编程? 这个别问我,我也不知道,或许是因为bi格高吧,哈哈,开玩笑啦。

  特性三 不再拘束于Servlet容器
  以前,我们的应用都运行于Servlet容器之中,例如我们大家最为熟悉Tomcat, Jetty...。而现在Spring WebFlux不仅能运行于传统的Servlet容器中(前提是容器要支持Servlet3.1,因为非阻塞IO是使用了Servlet3.1的特性),还能运行在支持NIO的Netty和Undertow中。


3、响应式编程的思想


  响应式编程框架主要采用了观察者模式。观察者模式的架构中被观察者(Observable)和观察者(Subscriber)处在不同的线程环境中时,由于者各自的工作量不一样,导致它们产生事件和处理事件的速度不一样。响应式流是通过背压来将两者的速度调整一致。


3.1背压


  背压是一种机制,这种机制可以让消费者主动告诉生产者调整生产速度。响应式流通过非阻塞背压实现将数据流从生产者传递到消费者,而不需要生产者阻塞。


3.2    响应式流接口


3.2.1发布者接口(生产者)


     public interface Publisher<T> {
        public void subscribe(Subscriber<? super T> s);
    }
  Mono 和Flux类都是实现了 org.reactivestreams.Publisher 接口,Mono代表0到1个元素的异步序列,Flux代表0到N个元素的异步序列。
  Mono和Flux类都是控制层返回给前端的响应类。
 3.2.2订阅者接口(消费者)
    public interface Subscriber<T> {
        public void onSubscribe(Subscription s);
        public void onNext(T t);
        public void onError(Throwable t);
        public void onComplete();
    }
  发布者(生产者)发布时先调用自身的subscribe方法,该方法会回调订阅者的onSubscribe方法,订阅者通过SubScription对象向发布者订阅n个数据。发布者通过回调订阅者的onNext方法,向其发送数据,数据发完,用onComplete方法告知订阅者数据已发完。onError方法处理其中产生的异常,并终止数据流。

 3.2.3订阅

    public interface Subscription {
        public void request(long n);
        public void cancel();
    }
  Subscription是一个订阅者订阅发布者的一个令牌。当订阅请求成功时,将其传给订阅者。订阅者使用令牌与发布者交互。
#### 3.2.4处理者
    public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
    }
  Process类负责转换订阅者和生产者管道中的元素

 4、如何创建一个webflux应用

4.1采用类似springmvc注解的方式使用webflux


4.1.1引入mavaen依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        
        
 4.1.2springboot的启动类新增一个注解@EnableWebFlux

    @SpringBootApplication
    @EnableWebFlux
    public class WebfluxApplication {
        public static void main(String[] args) {
            SpringApplication.run(WebfluxApplication.class, args);
        }
    }
4.1.3写dao层方法
     @Repository
    public interface PersonRepository extends ReactiveMongoRepository<PersonEntity,String> {

       /**
     * 根据name查找Person
     * @param name
     * @return
     */
        Flux<PersonEntity> findByUserName(String name);
}
4.1.4写controller层的方法
    @RestController
    public class IndexController
    {
        /**
         * 可以使用
         */
        @Autowired
        private PersonRepository personRepository;

        @GetMapping("/findByName/{name}")
        public Flux<PersonEntity> findByName(@PathVariable("name") String name){
             return personRepository.findByUserName(name)
                .map(x-> x)
                .defaultIfEmpty(new PersonEntity());
        }
    }
4.2 webflux的另一种router function模式
  在webflux中有Handler和Router 的概念,分别与springmvc中的controllerr和service相对应,通俗的将就是handler就是真正处理请求的bean,可以在handler中编写处理请求的逻辑,而Router就是如何让请求找到对应的handler中的方法处理,下面我们来实现一个简单的handler和router。
4.2.1 router类编写
    @Configuration
    public class RouterConfig {

        @Autowired
        private HelloWorldHandler helloWorldHandler;

        @Bean
        public RouterFunction<?> helloRouter() {
            return RouterFunctions.route(RequestPredicates.GET("/hello"), helloWorldHandler::helloWorld);
        }

    }
4.2.2 handler类的编写
    @Component
    public class HelloWorldHandler {

        public Mono<ServerResponse> helloWorld(ServerRequest request){
            return ServerResponse.ok()
                    .contentType(MediaType.TEXT_PLAIN)
                    .body(BodyInserters.fromObject("hello flux"));
        }
    
    }    
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值