簡介#
Spring 內部提供了事件機制,通過這個事件機制我們可以解耦系統的邏輯,實現松耦合的目的。 事件機制包含如下三個組件:
- 事件發佈者: 用來發布事件,發佈事件後系統其他組件可以接受到相應的事件, 由ApplicationPublisher實現
- 事件:可以自定義事件,如用戶創建,登錄等,可以通過繼承ApplicationEvent來實現自定義事件。
- 事件監聽者: Spring提供了@EventListener註解,可以通過在方法上使用此註解來監聽對應的事件
示例#
- 構造事件#
我們可以繼承ApplicationEvent來實現自己的事件,也可以直接使用ApplicationEvent 此外Spring還提供了許多其他事件:
<code>@Data
@ToString
public class PersonLoginEvent extends ApplicationEvent {
String message;
public PersonLoginEvent(Object source, String message) {
super(source);
this.message = message;
}
}
@Data
@ToString
public class PersonCreateEvent extends ApplicationEvent {
String message;
public PersonCreateEvent(Object source, String message) {
super(source);
this.message = message;
}
}/<code>
在系統中通過綁定ApplicationEventPublisher即可使用其發佈事件。一旦事件發佈立刻會被監聽器接收到, 發送消息是同步操作,如果希望異步發送消息可以聲明ApplicationEventMulticaster,使用Executor 來異步發送,推薦使用。
<code>@SpringBootApplication
public class UpscaleApplication implements CommandLineRunner,ApplicationListener<applicationstartedevent> {
\t@Autowired
\tApplicationEventPublisher publisher;
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
\tpublic static void main(String[] args) {
\t\tSpringApplication.run(UpscaleApplication.class, args);
\t}
\t@Override
\tpublic void onApplicationEvent(ApplicationStartedEvent event) {
log.info("Application Started!")
\t}
\t@Override
\tpublic void run(String... args) throws Exception {
\t\tlog.info("Start send message");
\t\tpublisher.publishEvent(new PersonCreateEvent("Created Person","Successfully create person!"));
publisher.publishEvent(new PersonLoginEvent("Person Login","Person login successfully!"));
\t}
}/<applicationstartedevent>/<code>
可以通過class來限制監聽的事件對象的類型,只有匹配的事件才會被處理
<code>import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class EventListenerService {
@EventListener(classes = {PersonCreateEvent.class})
public void handlePersonCreate(PersonCreateEvent event){
log.info("Peson create event:" + event);
}
@EventListener(classes = {PersonLoginEvent.class})
public void handlePersonLogin(PersonLoginEvent event){
log.info("Peson login event:" + event);
}
}
## 輸出
2019-06-14 19:45:19.963 INFO 9456 --- [ main] i.g.j.u.s.events.EventListenerService : Peson create event:PersonCreateEvent(message=Successfully create person)
2019-06-14 19:45:19.964 INFO 9456 --- [ main] i.g.j.u.s.events.EventListenerService : Peson login event:PersonLoginEvent(message=person login successfully)/<code>
事務監聽器#
如果要在數據庫操作之後發送通知消息,此時數據庫操作是在事務中執行的,事務中執行有可能成功也 有可能失敗,希望在數據庫操作成功之後接收到消息。此時我們需要TransactionalEventListener 它也是一種EventListener,只不過它和事務綁定,只有當事務完成之後才會回調此方法.
<code> @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handlePersonPersist(PersonCreateEvent event){
}/<code>
有如下四種事務階段
- BEFORE_COMMIT: 事務提交之前
- AFTER_COMMIT: 未指定時,默認使用
- AFTER_ROLLBACK: 事務回滾之後
- AFTER_COMPLETION: 事務成功提交
如果發送消息時,方法未使用Transaction進行標註,即使執行此方法,接收方也無法接收到消息。 此外,還需要滿足事務的階段與接收方一致
<code>## 消息發送方
public class PersonService {
@Autowired
PersonRepository repository;
@Autowired
EventPublisherService eventPublisherService;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Person savePerson(Person person){
Assert.notNull(person,"Person should not be null");
eventPublisherService.publishMessage(new PersonCreateEvent(person,"persist person"));
return repository.save(person);
}
}
## 消息接收方
@Service
@Slf4j
public class EventListenerService {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handlePersonPersist(PersonCreateEvent event){
log.info("*********************************************");
log.info("Peson transaction create event:" + event);
}
}/<code>
輸出
<code>2019-06-14 20:38:27.177 INFO 22835 --- [ main] i.g.j.u.s.events.EventListenerService : *********************************************
2019-06-14 20:38:27.177 INFO 22835 --- [ main] i.g.j.u.s.events.EventListenerService : Peson transaction create event:PersonCreateEvent(message=persist person)
2019-06-14 20:38:27.371 INFO 22835 --- [(3)-192.168.1.7] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'/<code>
總結#
EventListener可以在單應用中各組件來進行消息的傳遞實現系統松耦合的目的,但是無法跨應用進行消息通知 如果需要在多個微服務之間路由消息需要藉助第三方消息中間件kafka,rabbitmq.
閱讀更多 JetQin90 的文章
關鍵字: EventListener person 事件