黑马程序员技术交流社区

标题: 【郑州校区】Spring5.0响应式编程入门 [打印本页]

作者: 我是楠楠    时间: 2018-6-14 09:43
标题: 【郑州校区】Spring5.0响应式编程入门
本帖最后由 我是楠楠 于 2018-6-14 09:45 编辑

【郑州校区】Spring5.0响应式编程入门引言

​        响应式编程是一种面向数据流和变化传播的编程范式。使用它可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。我们可以使用声明的方式构建应用程序的能力,形成更加敏感和有弹性的应用,所以Spring 5在其核心框架中增加了反应系统,已经开始向声明式编程的范式转变。
响应式编程的优势应用场景Spring 5.0前瞻
作为Java中的首个响应式Web框架,Spring 5.0最大的亮点莫过于提供了完整的端到端响应式编程的支持。
      
如上图所示左侧是传统的基于Servlet的Spring Web MVC框架,右侧是spring 5.0新引入的基于Reactive Streams的Spring WebFlux框架,从上往下依次是:Router Functions,WebFlux,Reactive Streams三个新组件,其中:
示例代码1.创建项目
spring响应式开发,需要结合spring boot来完成,所以使用idea创建springboot项目,选择Spring Initializr选项,jdk选择1.8以上。        
选择下一步,设置groupId和artifactId。   
     
选择下一步,选择web选项中的Reactive web选项,表明要创建响应式项目,注意Spring Boot的版本为2.0.2。        
选择下一步,设置项目的目录,点击finish创建项目。  
      
2.设置服务端口
为了避免端口冲突,我们可以在项目的application.properties文件中配置服务端口。
server.port=90023.相关依赖包
打开项目的pom.xml文件,会发现以下几个依赖包
[AppleScript] 纯文本查看 复制代码
<dependencies>
    <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>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

其中:
小结
​            spring响应式开发需要结合spring boot来完成,同时需要引入spring-boot-starter-webflux和reactor-test两个依赖包来支持响应式开发。
4.使用webflux创建web应用
webflux的使用有两种方式,基于注解和函数式编程。这里使用函数式编程,具体操作如下:
4.1.创建实体类
[AppleScript] 纯文本查看 复制代码
public class Good {

    private int id;
    private String name;
    private String price;

    public Good(int id,String name,String price){
        this.id=id;
        this.name=name;
        this.price=price;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Good{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price='" + price + '\'' +
                '}';
    }
}

分析:        实体类没有什么特殊的操作,原来怎么操作现在还是怎么操作。
4.2.创建GoodGenerator
@Configuration
public class GoodGenerator {

    public Flux<Good> findGoods(){
        List<Good> goods = new ArrayList<>();
        goods.add(new Good(1,"小米","2000"));
        goods.add(new Good(2,"华为","4000"));
        goods.add(new Good(3,"苹果","8000"));
        return Flux.fromIterable(goods);
    }
}
分析:        这里的方法返回的是Flux类型的数据,Flux是RP中最基础的数据类型之一,对应的是多值数据的返回操作,在RP中还有Mono数据类型,也是最基础的数据类型之一,对应单值数据的返回操作。
注意:这里的GoodGenerator类要加上@Configuration注解。
4.3.创建GoodHandler
[AppleScript] 纯文本查看 复制代码
@Component
@Configuration
public class GoodHandler {

    private final Flux<Good> goods;

    public GoodHandler(GoodGenerator goodGenerator) {
        this.goods = goodGenerator.findGoods();
    }

    public Mono<ServerResponse> hello(ServerRequest request) {

        return ok().contentType(TEXT_PLAIN)
                .body(BodyInserters.fromObject("Hello Spring!"));
    }

    public Mono<ServerResponse> echo(ServerRequest request) {
        return ok().contentType(APPLICATION_STREAM_JSON)
                .body(this.goods,Good.class);
    }
}

分析:        Handler主要用来处理请求操作,并将Mono<ServerResponse>返回,Mono<ServerResponse>中会封装响应数据,响应数据如果是字符串可以使用:

[AppleScript] 纯文本查看 复制代码
ok().contentType(TEXT_PLAIN).body(BodyInserters.fromObject("Hello Spring!"));

操作,如果是集合数据可以使用:

[AppleScript] 纯文本查看 复制代码
ok().contentType(APPLICATION_STREAM_JSON).body(this.goods,Good.class)

操作。
4.4.创建GoodRouter
[AppleScript] 纯文本查看 复制代码
@Configuration
public class GoodRouter {
    @Bean
    public RouterFunction<ServerResponse> route(GoodHandler goodHandler) {

      return RouterFunctions
              .route(RequestPredicates.GET("/good")
                      .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),goodHandler::hello)
              .andRoute(RequestPredicates.GET("/goods")
                      .and(RequestPredicates.accept(MediaType.APPLICATION_STREAM_JSON)),goodHandler::echo);
    }

}

分析:        GoodRouter主要用来设置请求路径和转化HTTP请求,可以使用route()方法和andRoute方法设置多个请求路径和转化操作。
小结
​        HTTP请求会由GoodRouter转发给对应的Handler,Handler处理请求,并返回Mono<ServerResponse>,这里的Router类似@RequestMapping,Handler类似Controller
4.4.运行测试
​        实体类、GoodGenerator、GoodHandler、GoodRouter都已经创建完成了,我们可以运行项目打开浏览器进行测试.
浏览器输入http://localhost:9002/good,即可获取到"Hello Spring!"文本信息
浏览器输入http://localhost:9002/goods,即可获取到集合信息
到目前为止,一个简单的webflux示例已经完成。
4.5.单元测试
在项目中我们也可以使用使用一个Spring 5新引入的测试工具类,WebTestClient,专门用于测试RP应用,具体代码如下:

[AppleScript] 纯文本查看 复制代码
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Spring5demoApplicationTests {

    @Autowired
    private WebTestClient webTestClient;

    @Test
    public void helloTest() {
      String s=  webTestClient
                .get().uri("/good")
                .accept(MediaType.TEXT_PLAIN).exchange()
                .expectStatus().isOk().returnResult(String.class)
                .getResponseBody().blockFirst();

        System.out.println(s);
    }

    @Test
    public void findGoodsTest(){
        webTestClient.get().uri("/goods")
                .accept(MediaType.APPLICATION_STREAM_JSON)
                .exchange().expectStatus().isOk()
                .expectHeader().contentType(MediaType.APPLICATION_STREAM_JSON)
                .returnResult(Good.class)
                .getResponseBody().collectList();
    }
}

创建WebTestClient实例时可以看到,编写RP应用的单元测试,同样也是数据不落地的流式风格
总结
​        到此,spring 5.0的响应式编程就给大家介绍到这里,这里只是简单进行了一个响应式入门操作,但是也能够体现出响应式编程的特点。当然spring 5.0响应式编程也不是完美的,它在故障诊断、依赖库集成、数据存储以及Spring Security安全权限框架支持等方面还是有局限性的。​        
传智播客·黑马程序员郑州校区地址
河南省郑州市 高新区长椿路11号大学科技园(西区)东门8号楼三层
联系电话 0371-56061160/61/62
来校路线  地铁一号线梧桐街站A口出





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2