springboot2.x简单详细教程--高级篇幅之响应式编程(第十五章)

 

一、SprinBoot2.x响应式编程简介


    简介:讲解什么是reactive响应式编程和使用的好处

    1、基础理解:
        依赖于事件,事件驱动(Event-driven)
        一系列事件称为“流”
        异步
      
 非阻塞

1)买奶茶的案例(一个一个等待处理)

2)响应式编程

        观察者模式:服务员一直观察后台的情况,然后通知客户

    网上的一个例子:
        int b= 2;
        int c=3
        int a = b+c  //命令式编程后续b和c变化,都不影响a
        b=5;

        int b= 2;
        int c= 3
        int a = b+c  //响应式编程中,a的变化,会和b、c的变化而变化(事件驱动)
        b=5;

    2、官网:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-webflux


        SpingBoot2底层是用spring5,开始支持响应式编程,Spring又是基于Reactor试下响应式。

    

    学习资料
        1、reactive-streams学习资料:http://www.reactive-streams.org/
        2、web-flux相关资料:https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#spring-webflux

 总结响应式编程,必须每一个阶段都不阻塞,才能提升性能

二、SpringBoot2.x响应式编程webflux介绍


    简介:讲解SpringBoot2.x响应式编程介绍 Mono、Flux对象和优缺点
    
    1、Spring WebFlux是Spring Framework 5.0中引入的新的反应式Web框架
    与Spring MVC不同
,它不需要Servlet API,完全异步和非阻塞,并 通过Reactor项目实现Reactive Streams规范
    RxJava

    2、Flux和Mono  User List<User>
        1)简单业务而言:和其他普通对象差别不大,复杂请求业务,就可以提升性能
        2)通俗理解:
            Mono 表示的是包含 0 或者 1 个元素的异步序列 (序列理解成流)
                mono->单一对象 User     redis->用户ID-》唯一的用户Mono<User>  
            
            Flux 表示的是包含 0 到 N 个元素的异步序列
                flux->数组列表对象 List<User>   redis->男性用户->Flux<User>
            Flux 和 Mono 之间可以进行转换


    3、Spring WebFlux有两种风格基于功能和基于注解的基于注解非常接近Spring MVC模型,如以下示例所示:
        第一种:
          
        第二种:
         “WebFlux.fn”是功能变体,它将路由配置与请求的实际处理分开,如以下示例所示:

   @Configuration
public class RoutingConfiguration {

	@Bean
	public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
		return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
				.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
				.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
	}

}

@Component
public class UserHandler {

	public Mono<ServerResponse> getUser(ServerRequest request) {
		// ...
	}

	public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
		// ...
	}

	public Mono<ServerResponse> deleteUser(ServerRequest request) {
		// ...
	}
}

    4、Spring WebFlux应用程序不严格依赖于Servlet API,因此它们不能作为war文件部署也不能使用src/main/webapp目录
    
    5、可以整合多个模板引擎
        除了REST Web服务外,您还可以使用Spring WebFlux提供动态HTML内容。Spring WebFlux支持各种模板技术,包括Thymeleaf,FreeMarker

 
三、SpringBoot2.x webflux实战


    简介:webflux响应式编程实战
    
    1、WebFlux中,
请求和响应不再是WebMVC中的ServletRequest和ServletResponse,而是ServerRequest和ServerResponse

    2、加入依赖,如果同时存在sprin g-boot-starter-web,则会优先用spring-boot-starter-web
       

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.itcast</groupId>
	<artifactId>Springboot08_A</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
	</parent>
	<dependencies>
		<!-- <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>	 -->
		<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-webflux</artifactId>
			</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
    
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

      官网说明

 测试

1)

2)


    

    3、启动方式默认是Netty,8080端口

    Netty:高性能网络框架,异步非阻塞

    4、参考:https://spring.io/blog/2016/04/19/understanding-reactive-types

   5.模拟数据库实现CRUD

   1)service

package com.itcast.demo.service;

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

import org.springframework.stereotype.Service;

import com.itcast.demo.domain.User;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
public class UserService {

	 //模拟数据库
	 private static final Map<String,User> map =new HashMap<>();
	  static{//一创建对象就初始化map
		  map.put("1", new User("1", "小王1"));
		  map.put("2", new User("2", "小王2"));
		  map.put("3", new User("3", "小王3"));
		  map.put("4", new User("4", "小王4"));
		  map.put("5", new User("5", "小王5"));
		  map.put("6", new User("6", "小王6"));
		  map.put("7", new User("7", "小王7"));
		  map.put("8", new User("8", "小王8"));		  
	  }
	  //返回所有数据
	  public Flux<User> list(){
		  Collection<User> list = UserService.map.values();
		  return Flux.fromIterable(list);
	  }
	  //通过id查出
	  public Mono<User> getById(final String id){
		return   Mono.justOrEmpty(UserService.map.get(id));
	  }
	  
	  //通过id删除用户
	  public Mono<User> del(final String id){
		return  Mono.justOrEmpty(UserService.map.remove(id));
	  }
}

2)controller

package com.itcast.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.itcast.demo.domain.JsonData;
import com.itcast.demo.domain.User;
import com.itcast.demo.service.UserService;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * @作者po
 */
@RestController
@RequestMapping("/api/v1")
public class UserController {
    //@Autowired
	//private UserService userService;
	
	//通过构造的方式
	private final UserService userService;
	
    public UserController(final UserService userService ) {
		this.userService=userService;
	}
	@GetMapping("test")
	public Mono<String> Test01() {
		return Mono.just("hello Mono");
	}
	
    @GetMapping("getById")
	public Mono<User> getById(final String id){
		return userService.getById(id);
	}
    @GetMapping("del")
   	public Mono<User> del(final String id){
   		return userService.del(id);
   	}
    
    @GetMapping("list")
   	public Flux<User> list(){
   		return userService.list();
   	}
     
}

3)访问

4)list

5)del

6)调用list的时候,希望拿到一个值就返回,如何体现这种效果

     //import org.springframework.http.MediaType;
     //拿到一个值就返回,即2s就返回,produces不配就没有这样的效果
    @GetMapping(value="list",produces=MediaType.APPLICATION_STREAM_JSON_VALUE)
   	public Flux<User> list(){//延迟两秒
   		return userService.list().delayElements(Duration.ofSeconds(2));
   	}

应该:服务端的推送(像流水一样

四、WebFlux客户端WebClient讲解


    简介:讲解SpringBoot2.x WebFlux客户端WebClient的介绍和使用
        1、反应式客户端

        官网地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-webclient

实战

1)在测试

package com.domain;

import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;

import reactor.core.publisher.Mono;

public class WebClientTest {

	@Test
	  public void testBase(){
	    Mono<String> resp = WebClient.create()
	        .get()
	        //多个参数也可以直接放到map中,参数名与placeholder对应上即可
	        .uri("http://localhost:8080/api/v1/getById?id=1") //使用占位符
	        .accept(MediaType.APPLICATION_JSON)
	        .retrieve()
	        .bodyToMono(String.class);
	    System.out.println(resp.block());
	 
	  }
	
	@Test
	  public void testPlaceHolder(){
	    Mono<String> resp = WebClient.create()
	        .get()	       
	        .uri("http://localhost:8080/api/v1/getById?id={id}",1) //使用占位符
	        .accept(MediaType.APPLICATION_JSON)
	        .retrieve()
	        .bodyToMono(String.class);
	    System.out.println(resp.block());
	 
	  }
	
}

2)先启动主程序,再在方法上点JUnit Test

猜你喜欢

转载自blog.csdn.net/jianchilu/article/details/83931600
今日推荐