use*_*855 10 java spring event-handling spring-boot
我有一个奇怪的问题,涉及@TransactionalEventListener没有正确触发或行为按预期由另一个触发@TransactionalEventListener.
一般流程是:
所以这是课程(摘录).
public class AccountService {
@Transactional
public User createAccount(Form registrationForm) {
// Some processing
// Persist the entity
this.accountRepository.save(userAccount);
// Publish the Event
this.applicationEventPublisher.publishEvent(new RegistrationEvent());
}
}
public class AccountEventListener {
@TransactionalEventListener
@Transactional(propagation = Propagation.REQUIRES_NEW)
public MailEvent onAccountCreated(RegistrationEvent registrationEvent) {
// Some processing
// Persist the entity
this.accountRepository.save(userAccount);
return new MailEvent();
}
}
public class MailEventListener {
private final MailService mailService;
@Async
@EventListener
public void onAccountCreated(MailEvent mailEvent) {
this.mailService.prepareAndSend(mailEvent);
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码有效但我的目的是@TransactionalEventListener在我的MailEventListener课堂上使用.因此,那一刻我从改变@EventListener到@TransactionalEventListener的MailEventListener类.MailEvent不会被触发.
public class MailEventListener {
private final MailService mailService;
@Async
@TransactionalEventListener
public void onAccountCreated(MailEvent mailEvent) {
this.mailService.prepareAndSend(mailEvent);
}
}
Run Code Online (Sandbox Code Playgroud)
MailEventListener从未被触发过.所以我去查看Spring文档,它声明@Async @EventListener不支持由另一个事件的返回发布的事件.所以我改为ApplicationEventPublisher在AccountEventListener课堂上使用.
public class AccountEventListener {
@TransactionalEventListener
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void onAccountCreated(RegistrationEvent registrationEvent) {
// Some processing
this.accountRepository.save(userAccount);
this.applicationEventPublisher.publishEvent(new MailEvent());
}
}
Run Code Online (Sandbox Code Playgroud)
一旦我改变了上述内容,我MailEventListener现在将接收发送的事件,AccountEventListener但是在提交表单时网页会挂起,并且在一段时间后它会抛出一些异常,然后它还向我发送了大约9封相同的电子邮件到我的电子邮件帐户.
我添加了一些日志记录,发现我的AccountEventListener(this.accountRepository.save())在遇到异常之前实际运行了9次,这导致我MailEventListener执行了9次我相信,这就是为什么我在收件箱中收到了9封邮件.
这是Pastebin中的日志.
我不确定为什么以及导致它运行9次的原因.有一个在我的方法没有环路或任何东西,无论是在AccountService,AccountEventListener或MailEventListener.
谢谢!
所以我去查看Spring Documentation,它声明@Async @EventListener不支持由另一个事件的返回发布的事件.所以我改为在AccountEventListener类中使用ApplicationEventPublisher.
你的理解是不正确的.
该文件说:
异步侦听器不支持此功能.
这并不意味着
它声明@Async @EventListener不支持由另一个事件的返回发布的事件.
它的意思是:
此功能不支持从@Async @EventListener返回事件.
你的设置:
@Async
@TransactionalEventListener
public void onAccountCreated(MailEvent mailEvent) {
this.mailService.prepareAndSend(mailEvent);
}
Run Code Online (Sandbox Code Playgroud)
因为如文件中所述,不起作用:
如果事件未在托管事务的边界内发布,则除非显式设置fallbackExecution()标志,否则将丢弃该事件.如果事务正在运行,则根据其TransactionPhase处理事件.
如果使用调试,则可以看到如果事件是从事件侦听器返回的,则会在事务提交后发生,因此事件将被丢弃.
因此,如果您设置fallbackExecution = true文档中所述的内容,您的事件将正确收听:
@Async
@TransactionalEventListener(fallbackExecution = true)
public void onAccountCreated(MailEvent mailEvent) {
this.mailService.prepareAndSend(mailEvent);
}
Run Code Online (Sandbox Code Playgroud)
重复的行为看起来像一些重试行为,连接排队,耗尽池并抛出异常.除非您提供最小的源代码来重现问题,否则我无法识别它.
更新
阅读您的代码,根本原因现在很清楚.
看看你的设置 POST /registerPublisherCommon
MailPublisherCommonEvent并且AccountPublisherCommonEvent是它的子事件BaseEventcreateUserAccountPublisherCommon 发布类型的事件 AccountPublisherCommonEventMailPublisherCommonEventListener 已注册处理 MailPublisherCommonEventAccountPublisherCommonEventListener已注册处理BaseEvent和所有子事件.AccountPublisherCommonEventListener也出版MailPublisherCommonEvent(也是一个BaseEvent).阅读4 + 5,您将看到根本原因:AccountPublisherCommonEventListener发布MailPublisherCommonEvent也由其自身处理,因此发生无限事件处理.
要解决它,只需缩小它可以像你一样处理的事件类型.
注意
您的设置是为了MailPublisherCommonEvent工作而不管fallbackExecution旗帜,因为您正在发布它INSIDE A TRANSACTION,而不是OUTSIDE A TRANSACTION像您在问题中指定的那样(通过事件监听器返回).
| 归档时间: |
|
| 查看次数: |
262 次 |
| 最近记录: |