发布订阅设计模式,springboot的事件驱动模型

363 阅读2分钟

springboot事件驱动的配置和示例

定义事件:


public class UserCreatedEvent extends ApplicationEvent {

    private final User user;

    public UserCreatedEvent(Object source, User user) {
        super(source);
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}

定义线程池,用来异步执行任务:

@Configuration
@EnableAsync
public class CustomAsyncConfig implements AsyncConfigurer {
    @Bean
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("MyAsyncThread-");
        executor.initialize();
        return executor;
    }
}

处理事件:

@Component
public class UserEventListener {

    @EventListener
    @Async
    public void handleOrderCreatedEvent(UserCreatedEvent event) {
        String name = Thread.currentThread().getName();
        System.out.println("listen thread:"+name);
        User user = event.getUser();
        int i = 5 / 0;//报错用来测试异步执行不影响请求线程
        // 在这里可以进行与用户创建相关的后续处理,比如发送通知邮件、更新相关信息等
        System.out.println("用户 " + user.getName() + " 已创建,正在进行后续处理,如发送通知邮件等。");
    }
}

Controller层示例代码:


@Controller
public class BasicController {

    @Autowired
    private UserService userService;

    // http://127.0.0.1:8080/hello?name=lisi
    @RequestMapping("/hello")
    @ResponseBody
    public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {
        User user = new User();
        user.setName(name);
        user.setAge(18);
        userService.createUser(user);
        System.out.println("异步报错不受影响!");
        return "Hello " + name;
    }

    
}

Service层代码:


@Service
public class UserService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void createUser(User user) {
        // 这里可以进行实际的用户创建逻辑,比如保存用户信息到数据库等操作
        System.out.println("创建了用户!");
        // 假设用户创建成功后,发布用户创建事件,后续异步执行对应事件
        eventPublisher.publishEvent(new UserCreatedEvent(this, user));
    }
}

学习到的设计模式-观察者模式/发布订阅模式

发布-订阅模式(也称为 Pub/Sub 模式)涉及三个主要组件:

  • 发布者(Publisher):负责发布事件到事件通道。
  • 订阅者(Subscriber):订阅事件通道,对发布的事件进行响应。
  • 事件通道(Event Channel):负责管理事件和订阅者,确保所有发布的事件都能传递给所有订阅者。

利用java自定义实现一个事件驱动模型的例子:

订阅者:

// 订阅者接口
interface Subscriber {
    void update(Event event);
}

定义一个事件/主题类:

// 事件
public abstract class Event<T> {

    private T source;

    public Event(T source) {
        this.source = source;
    }

    public T getSource() {
        return source;
    }

    List<Subscriber> subscribers = new ArrayList<>();
    public void subscribe(Subscriber subscriber) {
        this.subscribers.add(subscriber);
    }
    public void unsubscribe(Subscriber subscriber) {
        this.subscribers.remove(subscriber);
    }
    public void notifySubscribers() {
        for (Subscriber subscriber : subscribers) {
            subscriber.update(this);
        }
    }
}

事件具体实现类,用户注册事件:

public class UserRegisterEvent<User> extends Event{

    public UserRegisterEvent(User source) {
        super(source);
    }
}

用户注册订阅者:

// 具体订阅者
class UserRegisterSubscriber implements Subscriber {
    private String name;

    public UserRegisterSubscriber(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public void update(Event event) {
        System.out.println(name + " 收到消息:" + event.getSource());
    }
}

发布者:

// 发布者
class Publisher {
    public void publish(Event event) {
        event.notifySubscribers();
    }
}

定义一个发布者/生产者:

发布者里保存了所有的订阅者或者说是消费者

public class Publisher {
    private List<EventConsumer> eventConsumers = new ArrayList<>();

    public void addConsumer(EventConsumer consumer) {
        eventConsumers.add(consumer);
    }

    public void removeConsumer(EventConsumer consumer) {
        eventConsumers.remove(consumer);
    }

    public void publishEvent(Event event) {
        for (EventConsumer consumer : eventConsumers) {
            if (consumer.isSubscribedTo(event.getTopic())) {
                consumer.handleEvent(event);
            }
        }
    }
}

测试用例:

public class Main {
    public static void main(String[] args) {
        User user = new User();
        user.setName("alice");
        user.setAge(18);


        UserRegisterEvent<User> event = new UserRegisterEvent<>(user);

        Subscriber subscriber1 = new UserRegisterSubscriber("ethan1");
        Subscriber subscriber2 = new UserRegisterSubscriber("ethan2");
        Subscriber subscriber3 = new UserRegisterSubscriber("ethan3");
        Subscriber subscriber4 = new UserRegisterSubscriber("ethan4");
        event.subscribe(subscriber1);
        event.subscribe(subscriber2);
        event.subscribe(subscriber3);
        event.subscribe(subscriber4);
        Publisher publisher = new Publisher();
        publisher.publish(event);
    }
}