SpringBoot 2.x(14): WebFlux 응답 프로그래밍

21162 단어
응답 프로그래밍 라이프 사례:
기존 방식:
한 무리의 사람들이 식당에 가서 밥을 먹습니다. 고객1은 종업원을 찾아 주문을 하고 종업원은 주문서를 백스테이지 요리사에게 건네주고 종업원은 기다립니다.
백스테이지 요리사가 밥을 지어 종업원에게 건네주고 종업원을 거쳐 다시 손님에게 건네준다.
종업원은 서버로 이해할 수 있다. 서버가 많을수록 처리할 수 있는 고객의 요청이 많다
응답 프로그래밍:
종업원은 고객 1의 요구를 기억하고 백스테이지 요리사에게 맡기고 고객 2의 요구를 기억하며 백스테이지 요리사에게 맡긴다.
요리사가 고객 1의 밥을 만들어 종업원에게 알려주고 종업원이 손님에게 밥을 배달한다.
요리사가 손님 2의 밥을 만들어 종업원에게 알리고 종업원이 손님 2에게 밥을 배달하는 것으로 추정된다.
 
일련의 사건을 흐름, 비동기 비막힘, 관찰자의 디자인 모델이라고 부른다
 
코드 사례:
전통:
int b=2; intc=3 inta=b+c/a가 부여된 후 b와 c의 변화는 ab=5에 영향을 주지 않는다.
 
응답 프로그래밍:
int b=2; int c=3 int a=b+c  b=5;//이때 a는 8로 변하고 a는 b, c의 변화에 따라 변화한다
 
SpringBoot2.x의 응답식 프로그래밍은 Spring5를 기반으로 합니다.
Spring5의 응답 프로그래밍은 Reactor와 Netty, Spring WebFlux를 기반으로 Spring MVC를 대체합니다.
 
응답식 프로그래밍의 가장 큰 핵심은 비장애물이다. 즉, 백그라운드의 모든 단계는 비장애물이어야 한다.
예를 들어 MySQL을 데이터베이스로 사용하는데 MySQL이 응답식 프로그래밍을 제공하지 않기 때문에 막힌다
따라서 응답 프로그래밍은 MySQL을 사용하지 말고 막히지 않는 NoSQL을 사용해야 한다
 
Spring WebFlux에는 기능 기반 및 메모 기반 두 가지 스타일이 있습니다.메모 기반은 다음 예와 같이 Spring MVC 모델에 매우 가깝습니다.
            @RestController 
            @RequestMapping(“/ users”)
             public  class MyRestController {

                @GetMapping(“/ {user}”)
                 public Mono  getUser( @PathVariable Long user){
                     // ...
                }

                @GetMapping(“/ {user} / customers”)
                 public Flux  getUserCustomers( @PathVariable Long user){
                     // ...
                }

                @DeleteMapping(“/ {user}”)
                 public Mono  deleteUser( @PathVariable Long user){
                     // ...
                }

            }

두 번째: 루트 설정과 요청의 실제 처리 분리
            @Configuration
             public  class RoutingConfiguration {

                @Bean
                 public RouterFunction  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  getUser(ServerRequest request){
                     // ...
                }

                public Mono  getUserCustomers(ServerRequest request){
                     // ...
                }

                public Mono  deleteUser(ServerRequest request){
                     // ...
                }
            }

Spring WebFlux 응용 프로그램은 Servlet API에 엄격하게 의존하지 않기 때문에 war 파일로 배치할 수 없고 src/main/webapp 디렉터리를 사용할 수 없습니다
여러 템플릿 엔진을 통합할 수 있으며, REST 외에도 Spring WebFlux를 사용하여 동적 HTML 콘텐츠를 제공할 수 있습니다.
Spring WebFlux는 Thymeleaf, FreeMarker 등 다양한 템플릿 기술을 지원합니다.
 
간단한 실전:
의존하다
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webfluxartifactId>
        dependency>

자동으로 생성되는 SpringBoot 프로젝트에는 test 의존도가 있습니다. 선택 사항입니다.
        <dependency>
            <groupId>io.projectreactorgroupId>
            <artifactId>reactor-testartifactId>
            <scope>testscope>
        dependency>

간단한 Controller:
package org.dreamtech.webflux.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import reactor.core.publisher.Mono;

@RestController
public class TestController {
    @GetMapping("/test")
    public Mono test() {
        return Mono.just("hello world");
    }
}

방문http://localhost:8080/test, hello world 설명 성공 표시
 
여기에서 Mono가 사용되고 뒤에는 Flux가 사용됩니다. 이들의 실현은 매우 복잡하지만 간단하게 이해할 수 있습니다.
User、List
1) 단순 업무의 경우: 다른 일반 대상과 차이가 크지 않고 복잡한 요청 업무로 성능을 향상시킬 수 있음 2) 통속적인 이해: 모노는 0 또는 1개의 요소를 포함하는 비동기 시퀀스 모노-> 단일 대상 User를 나타낸다. 예를 들어 redis에서 사용자 ID에 따라 유일한 사용자를 찾아낸 후 모노로 돌아간다
Flux는 0에서 N까지의 요소를 포함하는 비동기식 시퀀스 flux-> 그룹 목록 대상 목록을 나타냅니다. 예를 들어 redis에서 조건에 따라 성별이 남성인 사용자를 찾아서 Flux 3로 되돌려줍니다. Flux와 Mono 간에 변환할 수 있습니다.
 
진일보한 사용
User 엔티티 클래스의 삭제 및 수정 기능:
package org.dreamtech.webflux.domain;

public class User {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public User(String id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

}

Service:
package org.dreamtech.webflux.service;

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

import org.dreamtech.webflux.domain.User;
import org.springframework.stereotype.Service;

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

@Service
public class UserService {
    //  Map 
    private static final Map dataMap = new HashMap();
    static {
        dataMap.put("1", new User("1", "admin"));
        dataMap.put("2", new User("2", "John"));
        dataMap.put("3", new User("3", "Rose"));
        dataMap.put("4", new User("4", "James"));
        dataMap.put("5", new User("5", "Bryant"));
    }

    /**
     *  
     * 
     * @return
     */
    public Flux list() {
        Collection list = UserService.dataMap.values();
        return Flux.fromIterable(list);
    }

    /**
     *  ID 
     * 
     * @param id  ID
     * @return
     */
    public Mono getById(final String id) {
        return Mono.justOrEmpty(UserService.dataMap.get(id));
    }

    /**
     *  ID 
     * 
     * @param id  ID
     * @return
     */
    public Mono delete(final String id) {
        return Mono.justOrEmpty(UserService.dataMap.remove(id));
    }
}

Controller:
package org.dreamtech.webflux.controller;

import org.dreamtech.webflux.domain.User;
import org.dreamtech.webflux.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class UserController {
    private final UserService userService;

    public UserController(final UserService userService) {
        this.userService = userService;
    }

    /**
     *  ID 
     * 
     * @param id  ID
     * @return
     */
    @GetMapping("/find")
    public Mono findById(final String id) {
        return userService.getById(id);
    }

    /**
     *  
     * 
     * @return
     */
    @GetMapping("/list")
    public Flux list() {
        return userService.list();
    }

    /**
     *  ID 
     * 
     * @param id  ID
     * @return
     */
    @GetMapping("/delete")
    public Mono delete(final String id) {
        return userService.delete(id);
    }
}

정의된 세 개의 API에 액세스하여 SpringMVC와 거의 다를 수 없음
따라서 반환 지연 처리:
    @GetMapping("/list")
    public Flux list() {
        return userService.list().delayElements(Duration.ofSeconds(3));
    }

이 설정만 하면 3*list를 기다립니다.size 초 후에 모두 되돌아옵니다. 흐름의 특징을 돋보이게 하려면 설정해야 합니다.
    @GetMapping(value = "/list", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
    public Flux list() {
        return userService.list().delayElements(Duration.ofSeconds(3));
    }

이때 방문하면 3초가 지나면 대상 정보가 되돌아오는 것을 발견할 수 있다
 
WebClient 클라이언트를 사용하여 테스트:
package org.dreamtech.webflux;

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 test() {
        Mono bodyMono = WebClient.create().get().uri("http://localhost:8080/find?id=3")
                .accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(String.class);
        System.out.println(bodyMono.block());
    }
}

좋은 웹페이지 즐겨찾기