Spring提供了事件发布、监听的功能,在ApplicationContext中提供了一个publishEvent(ApplicationEvent event)来实现事件的发布,通过实现ApplicationListener来定义监听者的逻辑。

下面我们通过一个例子来说明。

1.定义一个事件

1
2
3
4
5
public class LogEvent extends ApplicationEvent {
public LogEvent(Object source) {
super(source);
}
}

2.定义事件监听者

1
2
3
4
5
6
7
8
@Component
public class LogEventListener implements ApplicationListener<LogEvent> {
@Override
public void onApplicationEvent(LogEvent logEvent) {
LogEventModel model = (LogEventModel) logEvent.getSource();
System.out.println("--LogEventListener:[device="+model.getDevice() +",phone="+model.getUserPhone()+",nickname="+model.getNickname()+"].");
}
}

这里的LogEventModel定义如下:

1
2
3
4
5
6
7
@Data
@Builder
public class LogEventModel {
private String device;
private String userPhone;
private String nickname;
}

3.写一个Spring的工具类,实现ApplicationContextAware,以便使用它来发布事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}

public static void publishEvent(ApplicationEvent event) {
applicationContext.publishEvent(event);
}
}

4.测试

1
2
3
4
5
6
7
8
9
10
11
12
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {Application.class})
public class SpringEventTest {

@org.junit.Test
public void test() {
LogEventModel model = LogEventModel.builder().device("ios").nickname("jack").userPhone("13888888888").build();
System.out.println("开始发布Spring Event");
SpringUtil.publishEvent(new LogEvent(model));
System.out.println("Spring Event发布完成。");
}
}

控制台日志:

1
2
3
开始发布Spring Event
--LogEventListener:[device=ios,phone=13888888888,nickname=jack].
Spring Event发布完成。

通过控制台日志,我们注意到事件监听处理逻辑跟主程序是同步执行的,如果想异步执行,可以在LogEventListener的onApplicationContext方法上加入@Async注解,另外在配置类中加入@EnableAsync来启用异步(如果使用Spring Boot,在启动类上加入即可)。

另外事件监听器也可以通过注解的方式来指定

1
2
3
4
5
6
7
8
9
10
@Component
public class LogEventListener2 {

@Async
@EventListener({LogEvent.class})
public void handle(LogEvent logEvent) {
LogEventModel model = (LogEventModel) logEvent.getSource();
System.out.println("--LogEventListener2:[device="+model.getDevice() +",phone="+model.getUserPhone()+",nickname="+model.getNickname()+"].");
}
}

通常,一些不重要的功能,比如日志记录、邮件发送、数据上报等情形可以考虑使用Spring提供的事件发布监听来优化。