spring webflux详细介绍

Spring WebFlux 是 Spring Framework 的一部分,它提供了构建响应式 Web 应用程序的能力。WebFlux 支持非阻塞 I/O,使得应用程序能够高效地处理大量并发请求。下面来详细介绍 Spring WebFlux。

1. 入门指南

1.1 安装和设置

为了开始使用 Spring WebFlux,你需要先安装 Java 和 Maven 或 Gradle。然后,你可以使用 Spring Initializr 来创建一个新的项目。以下是使用 Maven 的示例 pom.xml 文件:

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>webflux-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>webflux-demo</name>
    <description>Demo project for Spring WebFlux</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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 创建一个简单的 REST API

接下来,我们创建一个简单的 REST API。

import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class GreetingRouter {

    @Bean
    public RouterFunction<ServerResponse> routes(GreetingHandler greetingHandler) {
        return route(GET("/greeting"), greetingHandler::greet);
    }
}

@Component
class GreetingHandler {

    public Mono<ServerResponse> greet(ServerRequest request) {
        return ok()
                .contentType(APPLICATION_JSON)
                .body(Mono.just(new Greeting("Hello, World!")), Greeting.class);
    }
}

record Greeting(String message) {}

2. 响应式编程基础

2.1 Mono 和 Flux
  • Mono:表示单个结果的容器,类似于 Future<T>
  • Flux:表示零个、一个或多个结果的容器,类似于 Stream<T>
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class ReactiveBasics {

    public static void main(String[] args) {
        // Mono example
        Mono.just("Hello")
            .subscribe(System.out::println);

        // Flux example
        Flux.range(1, 10)
            .map(i -> i * 2)
            .subscribe(System.out::println);
    }
}

3. 控制器与路由

3.1 使用 @RestController

使用 @RestController@GetMapping 等注解来定义 RESTful 控制器。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class GreetingController {

    @GetMapping("/greeting")
    public Mono<Greeting> greet() {
        return Mono.just(new Greeting("Hello, World!"));
    }
}

4. 处理表单和请求体

4.1 处理 POST 请求

使用 @PostMapping 注解来处理 POST 请求,并通过 @RequestBody 注解来读取请求体。

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class ItemController {

    @PostMapping("/items")
    public Mono<Item> createItem(@RequestBody Mono<Item> itemMono) {
        return itemMono
            .map(item -> {
                // Perform some operation on the item
                return item;
            });
    }
}

record Item(String name, String description) {}

如果要使用Spring Data R2DBC和数据库交互,则Item定义如下:

import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import reactor.core.publisher.Mono;

@Table("items")
public record Item(
    @Id
    Long id,
    String name,
    String description
) {
    public Item {
        // 如果没有提供 id,则默认为 null
        this.id = (this.id == null) ? null : this.id;
    }
}

pom.xml添加依赖:

<dependency>        
    <groupId>org.springframework.boot</groupId>     
    <artifactId>spring-boot-starter-data-r2dbc</artifactId> 
</dependency>

application.yml添加配置:

spring: 
  r2dbc: 
    url: r2dbc:postgresql://localhost:5432/mydb
    username: myuser 
    password: mypassword 
    database: mydb

5. 异常处理

5.1 使用 @ExceptionHandler

使用 @ControllerAdvice@ExceptionHandler 来处理异常。

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import reactor.core.publisher.Mono;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = IllegalArgumentException.class)
    public Mono<ResponseEntity<String>> handleIllegalArgumentException(IllegalArgumentException ex) {
        return Mono.just(new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST));
    }
}

6. 数据访问

6.1 使用 Spring Data R2DBC

使用 Spring Data R2DBC 来访问关系型数据库。

import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Repository
public interface ItemRepository extends ReactiveCrudRepository<Item, Long> {
    Flux<Item> findByName(String name);
}

// 在 ItemController 中使用 ItemRepository
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class ItemController {

    private final ItemRepository itemRepository;

    @Autowired
    public ItemController(ItemRepository itemRepository) {
        this.itemRepository = itemRepository;
    }

    @GetMapping("/items")
    public Flux<Item> getItems() {
        return itemRepository.findAll();
    }
}

7. 安全性和认证

7.1 使用 Spring Security

使用 Spring Security 来保护你的 WebFlux 应用程序。

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        return http
            .authorizeExchange()
                .pathMatchers("/greeting").permitAll()
                .anyExchange().authenticated()
                .and()
            .formLogin()
                .and()
            .build();
    }
}

8. 高级主题

8.1 非阻塞 I/O

使用非阻塞 I/O 来提高性能。

import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

public class NonBlockingIOExample {

    public static void main(String[] args) {
        WebClient client = WebClient.create("https://api.example.com");

        Mono<String> response = client.get()
            .uri("/data")
            .retrieve()
            .bodyToMono(String.class);

        response.subscribe(System.out::println);
    }
}
8.2 自定义函数式路由

使用函数式编程风格来定义路由。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;

@Configuration
public class FunctionalRoutingConfig {

    @Bean
    public RouterFunction<ServerResponse> routerFunction() {
        return RouterFunctions
            .route(GET("/greeting"), req -> ServerResponse.ok().bodyValue("Hello, World!"))
            .andRoute(GET("/items"), req -> ServerResponse.ok().bodyValue("List of items"));
    }
}

9. 性能优化

9.1 缓存

使用 Spring Cache 或其他缓存机制来提高性能。

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

@Service
public class ItemService {

    @Cacheable(value = "items", key = "#id")
    public Mono<Item> getItem(Long id) {
        // Fetch the item from the database or other source
        return Mono.just(new Item("Name", "Description"));
    }
}
9.2 并发处理

利用并行处理来提高并发能力。

import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;

@Service
public class ItemService {

    public Flux<Item> fetchItemsInParallel() {
        return Flux.range(1, 100)
            .parallel(10)
            .runOn(Schedulers.boundedElastic())
            .map(i -> new Item("Name " + i, "Description " + i))
            .sequential();
    }
}

10. 测试

10.1 单元测试

使用 JUnit 和 MockWebServer 进行单元测试。

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Mono;

@WebFluxTest
public class GreetingControllerTest {

    @Autowired
    private WebTestClient webTestClient;

    @Test
    public void shouldReturnDefaultGreeting() {
        webTestClient.get().uri("/greeting")
            .exchange()
            .expectStatus().isOk()
            .expectBody(String.class).isEqualTo("Hello, World!");
    }
}

11. 部署

11.1 生产部署

使用 Spring Boot 打包工具将应用打包成可执行的 JAR 文件。

mvn clean package
java -jar target/webflux-demo-0.0.1-SNAPSHOT.jar

12. 进阶主题

12.1 WebSocket 支持

使用 WebSockets 实现实时通信。

import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Mono;

public class ChatWebSocketHandler implements WebSocketHandler {

    @Override
    public Mono<Void> handle(WebSocketSession session) {
        return session.receive()
            .map(WebSocketMessage::getPayloadAsText)
            .doOnNext(message -> System.out.println("Received message: " + message))
            .then(session.send(Mono.just(session.textMessage("Echo: " + message))))
            .then();
    }
}
12.2 客户端支持

使用 Spring WebFlux Client 来实现客户端逻辑。

import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

public class WebClientExample {

    public static void main(String[] args) {
        WebClient client = WebClient.create("https://api.example.com");

        Mono<String> response = client.get()
            .uri("/data")
            .retrieve()
            .bodyToMono(String.class);

        response.subscribe(System.out::println);
    }
}

13. 结论

Spring WebFlux 提供了强大的工具来构建响应式的 Web 应用程序。随着你对这些特性的熟悉程度加深,你可以根据自己的需求来扩展和定制你的应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

svygh123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值