Spring的Event事件驱动案例

404 阅读3分钟

一、前言

目的: 我们创建一个对象,一旦这个对象中的内容发生了变更,就会利用Event事件驱动抛出一个相应的事件,其他的观察者一旦观察到该对象的内容发生了变化,那么就可以做出响应的应对和调整!

模式应用: 观察者模式

应用场景: SpringEvent在我认为是一个解决业务解耦的办法,运用了观察者模式,用于当一个业务的更改后,需要改变其他业务的状态。例如一个商品的下单,需要修改商品的库存,以及商家的消息发送等等。之前我做这种业务解耦的时候,使用的时消息队列进行解耦,但如果只是为了解耦而整合了消息队列就有点大材小用了,我认为可以使用Spring的Event事件驱动来满足需求(需要容忍宕机丢失等问题,如果无法容忍,还是需要使用消息队列)!

说明: 此案例为了实现,我们创建的Person对象,我们使用一个PersonChangeEvent来实现Event事件驱动,使用代码对Person进行的增删改等操作使用PeronEventPublisher来进行发布服务,使用PeronEventListener来进行监听,通过监听到对应的事件,我们来执行相应的逻辑,可以加些后续操作,例如添加缓存、更新缓存等!

二、代码实现

2.1 被观察的对象: Person

package com.ssm.user.event;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    private String name;

    private Integer age;
    
}

2.2 对应的Event事件驱动: PersonChangeEvent

package com.ssm.user.event;

import lombok.Data;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;

@Getter //当类中没有默认的构造函数时(继承ApplicationEvent后,重写构造方法)不能使用@Data注解
//想要get到PersonChangeEvent类中的属性可加@Getter注解来实现
public class PersonChangeEvent extends ApplicationEvent { 
//自定义event要继承ApplicationEvent(发布事件时对象要为ApplicationEvent,所以继承)

    private Person person;

    private String op;

    public PersonChangeEvent(Person person, String op) {
        super(person);
        this.person = person;
        this.op = op;
    }

}

2.3 相应的Event事件发布: PersonEventPublisher

package com.ssm.user.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class PersonEventPublisher {

    //spring容器初始化时已加载,可直接使用注解注入
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher; 



    public void createPerson(Person person) {
        //想要发布事件,对象就要是ApplicationEvent类型
        applicationEventPublisher.publishEvent(new PersonChangeEvent(person, "create"));
    }

    public void updatePerson(Person person) {
        applicationEventPublisher.publishEvent(new PersonChangeEvent(person, "update"));
    }
}

2.4 相应的Event事件监听: PersonEventListener

package com.ssm.user.event;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.event.TransactionalEventListener;

@Service
@Slf4j
public class PersonEventListener {
    /**
     * @TransactionalEventListener 事务事件监听
     * 在默认情况下仅仅会被事务中发布的事件触发,如果需要在没有事务也能当作普通时间监听器触发,那么需要将fallbackExecution属性设置为true。
     */
    @TransactionalEventListener(fallbackExecution = true)
    public void listenCreateEvent(PersonChangeEvent personChangeEvent) {
        switch (personChangeEvent.getOp()) {
            case "create" :
                // 自定义监听后需要执行的逻辑
                // 可以加些后续操作,例如添加缓存、更新缓存等
                log.info("创建Person对象:{}", JSON.toJSONString(personChangeEvent.getPerson()));
                break;

            case "update":
                log.info("更新Person对象:{}", JSON.toJSONString(personChangeEvent.getPerson()));
                break;

            default:
                break;
        }
    }
}

2.5 测试结果

package com.ssm.user;

import com.ssm.user.event.Person;
import com.ssm.user.event.PersonEventPublisher;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest(classes = {UserApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
@Slf4j
public class PersonChangeTest {

    @Autowired
    private PersonEventPublisher personEventPublisher;

    @Test
    public void test() {
        Person person = new Person("ssm", 18);
        personEventPublisher.createPerson(person);
        person.setAge(20);
        personEventPublisher.updatePerson(person);
    }
}

image.png

结论: 可以看到,我们在PeronEventPublisher和PeronEventListener中编写了创建和更新相关的操作,当我们对Person类进行操作的时候,只要调用相应的发布事件,那么在对应的监听事件就会执行相关后续操作!