標準 ApplicationListener 無序、異步執行,無法滿足「嚴格順序、上一步通過才執行下一步、同步阻塞」的業務流程(如多級審核、流水線任務)。
SmartApplicationListener 繼承 ApplicationListener,新增三大能力:
getOrder():定義執行優先級(值越小越先執行)。supportsEventType():聲明關心的事件類型,避免無關事件干擾。supportsSourceType():聲明關心的事件源類型,精準過濾。public class AuditEvent extends ApplicationEvent {
private Boolean status = true; // 當前審核狀態
private String work; // 申報作品
private String advice = "待審核"; // 審核意見
public AuditEvent(Object source, String work) {
super(source);
this.work = work;
}
// getter/setter 略
}
public class XiaoBai implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void reportWork(String work) {
AuditEvent event = new AuditEvent(this, work);
applicationContext.publishEvent(event); // 同步發布,阻塞直到所有監聽器完成
System.out.println("最終結果: " + event.getStatus() + " -- " + event.getAdvice());
}
@Override public void setApplicationContext(ApplicationContext ctx) { this.applicationContext = ctx; }
}
// 學校級審核 (Order=1)
public class SchoolListener implements SmartApplicationListener {
@Override public void onApplicationEvent(ApplicationEvent event) {
AuditEvent e = (AuditEvent) event;
System.out.println("[學校] 狀態:" + e.getStatus() + " 意見:" + e.getAdvice());
e.setStatus(true);
e.setAdvice("學校: 有創意,通過!");
}
@Override public int getOrder() { return 1; }
@Override public boolean supportsEventType(Class extends ApplicationEvent> t) { return AuditEvent.class == t; }
@Override public boolean supportsSourceType(Class> t) { return XiaoBai.class == t; }
}
// 省級審核 (Order=2)
public class ProvinceListener implements SmartApplicationListener {
@Override public void onApplicationEvent(ApplicationEvent event) {
AuditEvent e = (AuditEvent) event;
if (!e.getStatus()) return; // 上級駁回則跳過
System.out.println("[省級] 狀態:" + e.getStatus() + " 意見:" + e.getAdvice());
e.setStatus(true);
e.setAdvice("省級: 還行,通過!");
}
@Override public int getOrder() { return 2; }
@Override public boolean supportsEventType(Class extends ApplicationEvent> t) { return AuditEvent.class == t; }
@Override public boolean supportsSourceType(Class> t) { return XiaoBai.class == t; }
}
// 國家級審核 (Order=3)
public class CountryListener implements SmartApplicationListener {
@Override public void onApplicationEvent(ApplicationEvent event) {
AuditEvent e = (AuditEvent) event;
if (!e.getStatus()) return;
System.out.println("[國家] 狀態:" + e.getStatus() + " 意見:" + e.getAdvice());
e.setStatus(true);
e.setAdvice("國家: 勉強通過!");
}
@Override public int getOrder() { return 3; }
@Override public boolean supportsEventType(Class extends ApplicationEvent> t) { return AuditEvent.class == t; }
@Override public boolean supportsSourceType(Class> t) { return XiaoBai.class == t; }
}
<bean id="schoolListener" class="com.example.event.SchoolListener"/>
<bean id="provinceListener" class="com.example.event.ProvinceListener"/>
<bean id="countryListener" class="com.example.event.CountryListener"/>
<bean id="xiaoBai" class="com.example.event.XiaoBai"/>
public class MainTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("event-flow.xml");
XiaoBai xb = ctx.getBean(XiaoBai.class);
xb.reportWork("智能機器人");
}
}
[學校] 狀態:true 意見:待審核 [省級] 狀態:true 意見:學校: 有創意,通過! [國家] 狀態:true 意見:省級: 還行,通過! 最終結果: true -- 國家: 勉強通過!
| 機制 | 說明 |
|---|---|
| 同步阻塞 | publishEvent 默認同步調用所有監聽器,線程阻塞直到最後一個返回。 |
| 順序保證 | Spring 根據 getOrder() 升序排序監聽器,同 Order 無序。 |
| 狀態傳遞 | 事件對象在監聽器鏈中傳遞,可攜帶可變狀態 (如 status, advice)。 |
| 短路終止 | 監聽器中設置 status=false,後續監聽器判斷跳過,實現「一票否決」。 |
| 類型過濾 | supportsEventType/SourceType 避免無關事件誤觸發,提升性能與安全性。 |
@Configuration
@EnableAsync
public class AsyncEventConfig {
@Bean
public ApplicationEventMulticaster applicationEventMulticaster(TaskExecutor executor) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(executor); // 異步執行
return multicaster;
}
}
// 監聽器添加 @Async
@Component
public class AsyncSchoolListener implements SmartApplicationListener {
@Async @Override public void onApplicationEvent(ApplicationEvent event) { ... }
}
注意:異步模式下失去順序保證與狀態傳遞語義,需引入消息隊列/狀態機框架協調。
| 特性 | ApplicationListener | SmartApplicationListener |
|---|---|---|
| 順序控制 | 無 (依賴 @Order 注解於類上,但不標準) | getOrder() 標準接口 |
| 事件類型過濾 | 泛型擦除導致運行時無法精準判斷 | supportsEventType() 精確判斷 |
| 事件源過濾 | 無 | supportsSourceType() 精確判斷 |
| 適用場景 | 簡單解耦、異步通知、日誌記錄 | 有序流水線、狀態機、多級審批、管道過濾 |
SmartApplicationListener 通過 getOrder()、類型過濾、同步阻塞發布,將 Spring 事件機制從「廣播通知」升級為「有序流水線處理器」。結合事件對象攜帶可變狀態,可優雅實現多級審核、數據清洗管道、初始化鏈等強順序業務場景,是 Spring 事件編程的進階利器。