最近公司有一个消息推送的项目代码交接到了我手上。我熟悉代码的时候,发现项目中用到了 Reactor 的异步编码方式。所以就想稍稍做些了解

一、第一个Demo
  1. 首先可以去 https://start.springboot.io/ 创建一个简单的 Spring Boot Demo,然后下载解压。

  2. 先来简单看一下我的 Demo 项目的目录层级结构吧:
    秋天里第一个Demo——Spring Reactor_Reactor

  3. 当启动应用时,调用http://localhost:8080/api/test,向eventHandler的topic发送User事件,监听器即可接收到相关的事件并处理。

1.1 Maven项目配置文件pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.reactor</groupId>
    <artifactId>spring-reactor-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-reactor-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
            <version>1.1.6.RELEASE</version>
        </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 Spring Boot的主程序

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

1.3 实体类 User

package com.example.reactor.demo.dto;

public class User {

    private String firstName;

    private String lastName;

    private String address;

    private String city;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "User{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", address='" + address + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

1.4 将 Reactor 交给 Spring 管理

package com.example.reactor.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.Environment;
import reactor.core.Reactor;
import reactor.core.spec.Reactors;

@Configuration
public class ReactorConfig {

    @Bean
    public Environment reactorEnv() {
        return new Environment();
    }

    @Bean
    public Reactor createReactor() {
        return Reactors.reactor()
                .env(reactorEnv())
                .dispatcher(Environment.THREAD_POOL)
                .get();
    }
}

1.5 控制器类

package com.example.reactor.demo.controller;

import com.example.reactor.demo.dto.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import reactor.core.Reactor;
import reactor.event.Event;

@RestController
@RequestMapping("/api")
public class ApiController {

    @Autowired
    private Reactor reactor;

    @RequestMapping("/test")
    public String test() {
        User user = new User();
        user.setFirstName("Chetan");
        user.setLastName("Birajdar");
        user.setAddress("410 S Hauser");
        user.setCity("Los Angeles");
        reactor.notify("eventHandler", Event.wrap(user));
        System.out.println("Yeah, I sent something for you!!");
        return "Sent";
    }
}

通过 Reactor 的实例方法 notify 发送数据。

1.6 事件监听器

package com.example.reactor.demo.listener;

import com.example.reactor.demo.dto.User;
import com.example.reactor.demo.service.UserService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.Reactor;
import reactor.event.Event;
import reactor.function.Consumer;

import static reactor.event.selector.Selectors.$;

@Component
public class UserEventListener implements Consumer<Event<User>>, InitializingBean {

    @Autowired
    private UserService userService;

    @Autowired
    private Reactor reactor;

    @Override
    public void accept(Event<User> userEvent) {
        userService.saveUser(userEvent.getData());
    }

    @Override
    public void afterPropertiesSet() {
        reactor.on($("eventHandler"), this);
    }
}

指定接收者/消费者:通过 Reactor 的实例方法 on 将事件绑定到指定的监听器。

1.7 服务类 Service

package com.example.reactor.demo.service;

import com.example.reactor.demo.dto.User;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void saveUser(User data) {
        System.out.println("Saving user: " + data);
    }
}
参考文档

Spring Boot集成Reactor事件处理框架的简单示例