SpringBoot的事件监听

spring boot中事件的使用和发布

Spring的事件

ApplicationStartedEvent

SpringBoot启动监听类

SpringBoot启动开始的时候执行的事件,在该事件中可以获取到SpringApplication对象,可做一些执行前的设置。

1
2
3
4
5
6
7
8
9
public class MyApplicationStartingEventListener implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
SpringApplication application = applicationStartingEvent.getSpringApplication();
application.setBannerMode(Banner.Mode.OFF);
System.out.println("--------- execute MyApplicationStartingEventListener----------");
}

}

ApplicationEnvironmentPreparedEvent

SpringBoot配置环境事件监听

SpringBoot对应Environment已经准备完毕,但此时上下文context还没有创建。

在该监听中获取到ConfigurableEnvironment后可以对配置信息做操作,例如:修改默认的配置信息,增加额外的配置信息等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyApplicationEnvironmentPreparedEventListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
MutablePropertySources maps = environment.getPropertySources();
for (PropertySource<?> ps : maps) {
System.out.println(ps.getName() + "-----");
System.out.println(ps.getSource() + "-----");
System.out.println(ps.getClass() + "-----");
}
}

}

ApplicationPreparedEvent

Spring Boot上下文context创建完成,但此时spring中的bean是没有完全加载完成的。

在获取完上下文后,可以将上下文传递出去做一些额外的操作。在该监听器中是无法获取自定义bean并进行操作的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyApplicationPreparedEventListener implements ApplicationListener<ApplicationPreparedEvent> {

@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
ConfigurableApplicationContext context = event.getApplicationContext();
passContextInfo(context);
}

/**
* 传递上下文
* @param cac
*/
private void passContextInfo(ApplicationContext cac) {
//dosomething()
}
}

ApplicationReadyEvent

Spring Boot 加载完成时候执行的事件

1
2
3
4
5
6
7
public class MyApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
applicationReadyEvent.getApplicationContext();
System.out.println("springboot启动完成");
}
}

自定义事件

  • ApplicationEvent:Spring的事件接口
  • ApplicationListener:Spring的事件监听器接口,所有的监听器都实现该接口
  • ApplicationEventPublisher:Spring的事件发布接口,ApplicationContext实现了该接口
  • ApplicationEventMulticaster:Spring事件机制中的事件广播器,默认实现SimpleApplicationEventMulticaster

1. 自定义事件源和实体

消息实体类

1
2
3
4
5
6
7
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MessageEntity {
private Integer code;
private String message;
}

自定义事件源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyEvent extends ApplicationEvent {

private MessageEntity messageEntity;


public MyEvent(Object source, MessageEntity messageEntity) {
super(source);
this.messageEntity = messageEntity;
}

public MessageEntity getMessageEntity(){
return this.messageEntity;
}
}

2. 监听类

使用 @EventListener 的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Slf4j
@Component
public class MyEventListener {

/*@EventListener
public void handlerEvent(Object event) {
log.info("监听到事件:{}",event);
}*/

@EventListener
public void handlerMyEvent(MyEvent event) {
log.info("监听到MyEvent事件,消息为:{},发布时间:{}",
event.getMessageEntity(), event.getTimestamp());
}

/**
* 监听code为100的事件
*/
@EventListener(condition = "#event.messageEntity.code==100")
public void handlerMyEventByCondition(MyEvent event) {
log.info("监听到code为100的MyEvent事件,消息为:{},发布时间:{}",
event.getMessageEntity(), event.getTimestamp());
}

}

继承 ApplicationListener 的方式

1
2
3
4
5
6
7
8
@Slf4j
@Component
public class MyEventListener2 implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.info("MyEventListener2接收到事件:{}",event.getMessageEntity());
}
}

使用@EventListener的condition可以实现更加精细的事件监听,condition支持SpEL表达式,可根据事件源的参数来判断是否监听。

3. 发布事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@RestController
public class TestController {

@Autowired
private ApplicationEventPublisher publisher;

@Autowired
private AccountRepository repository;

@GetMapping("/push/100")
public String push0() {
publisher.publishEvent(new MyEvent(this, new MessageEntity(100, "code为100的消息")));
return "事件为100发布成功";
}

@GetMapping("/push/obj")
public String pushObj() {
publisher.publishEvent(new MessageEntity(1, "code为1的事件"));
return "对象发布成功";
}

@GetMapping("/save")
public String testSave() {
Account account = repository.save(new Account("test", 100.0));
publisher.publishEvent(new MyEvent(this, new MessageEntity(300, "保存成功:" + account)));
return "保存成功";
}

}

4. 启动类

加入自定义的监听类

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class Springboot13EventApplication {

public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(Springboot13EventApplication.class);
builder.listeners(new MyApplicationStartingEventListener());
builder.listeners(new MyApplicationReadyEventListener());
// builder.listeners(new MyEventListener2());
builder.run(args);
}

}

5. 启动应用,测试

http://localhost:8088/push

InlWa6.png

http://localhost:8088/push/100

InlbqI.png

http://localhost:8088/save

InlxJS.png

异步监听处理

在需要异步处理时,可以在方法上加上@Async进行异步化操作。此时,可以定义一个线程池,同时开启异步功能,加入@EnableAsync。

1
2
3
4
5
6
7
8
9
/**
* 监听code为100的事件
*/
@Async
@EventListener(condition = "#event.messageEntity.code==100")
public void handlerMyEventByCondition(MyEvent event) {
log.info("监听到code为100的MyEvent事件,消息为:{},发布时间:{}",
event.getMessageEntity(), event.getTimestamp());
}

关于事务绑定事件

模拟转账

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Service
public class AccountService {

@Autowired
private AccountRepository accountRepository;

@Transactional
public void transfer(){
Double money = 100d;
Account source = accountRepository.findById(31).get();
Account target = accountRepository.findById(32).get();
// 源账户减钱
source.setMoney(source.getMoney() - money);

// int i = 1/0;
// 目标账户加钱
target.setMoney(target.getMoney() + money);

accountRepository.save(source);
accountRepository.save(target);
}

}

方便测试。写死了就

1
2
3
4
5
6
@GetMapping("/transfer")
public String testTransaction(){
accountService.transfer();
publisher.publishEvent(new MyEvent(this, new MessageEntity(4, "转账成功")));
return "转账成功";
}

监听的方法 用@TransactionalEventListener 注解

1
2
3
4
5
6
7
8
/**
* 监听code为4的事件
*/
@TransactionalEventListener(condition = "#event.messageEntity.code==4")
public void handlerMyEventByCondition2(MyEvent event) {
log.info("监听到code为4的MyEvent事件,消息为:{},发布时间:{}",
event.getMessageEntity(), event.getTimestamp());
}

测试

没有异常的情况访问

InJU4P.png

接收到了事件

InJsBj.png

有异常的情况访问

InJVB9.md.png

没有接收到事件

InJntx.png

  • Copyrights © 2020-2023 夕子学姐
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信