@TransactionalEventListener 注释方法未在@Transactional 测试中调用
@TransactionalEventListener annotated method not invoked in @Transactional test
我正在尝试按照下面 post 中提到的示例从实体发布领域事件:
但是我还没有设法 Spring 调用我的带有 @TransactionalEventListener 注释的方法。
参见下面的实体、服务、事件侦听器和测试代码:
@Entity
public class Book extends AbstractAggregateRoot<Book>
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true)
private String isbn;
@Column
private String name;
public Book(String isbn, String name)
{
this.isbn = isbn;
this.name = name;
}
public void purchase()
{
registerEvent(new BookPurchasedEvent(id));
}
// getters omitted for brevity
}
服务:
@Service
@Transactional
public class BookService
{
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository)
{
this.bookRepository = bookRepository;
}
public void purchaseBook(Integer bookId)
{
Book book = bookRepository.findById(bookId)
.orElseThrow(NoSuchElementException::new);
book.purchase();
bookRepository.save(book);
}
}
听众:
@Service
public class EventListener
{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@TransactionalEventListener
public void handleEvent(BookPurchasedEvent event)
{
logger.info("Received event {}", event);
}
}
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class BookEventsTest
{
@Autowired
private BookService bookService;
@Autowired
private EntityManager entityManager;
@Test
public void test()
{
Book book = new Book("abcd-efgh", "El Quijote");
book = entityManager.merge(book);
bookService.purchaseBook(book.getId());
}
}
来自侦听器的日志消息未被记录。虽然它在部署为 REST 服务并被调用时有效,例如通过邮递员
知道了。由于我的测试是用@Transactional 注释的,因此包装测试方法的事务将被回滚。因此,不会调用带有 @TransactionalEventListener 注释的方法,因为默认情况下它会在 TransactionPhase.AFTER_COMMIT 阶段触发(除非交易成功,否则我对调用它不感兴趣)。所以测试的工作版本如下所示:
@RunWith(SpringRunner.class)
@SpringBootTest
public class BookEventsTest
{
@Autowired
private BookService bookService;
@Autowired
private BookRepository bookRepository;
@MockBean
private EventListener eventListener;
private Book book;
@Before
public void init() {
book = bookRepository.save(new Book("abcd-efgh", "El Quijote"));
}
@After
public void clean() {
bookRepository.deleteAll();
}
@Test
public void testService()
{
bookService.purchaseBook(book.getId());
then(eventListener)
.should()
.handleEvent(any(BookPurchasedEvent.class));
}
}
我正在尝试按照下面 post 中提到的示例从实体发布领域事件:
但是我还没有设法 Spring 调用我的带有 @TransactionalEventListener 注释的方法。
参见下面的实体、服务、事件侦听器和测试代码:
@Entity
public class Book extends AbstractAggregateRoot<Book>
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true)
private String isbn;
@Column
private String name;
public Book(String isbn, String name)
{
this.isbn = isbn;
this.name = name;
}
public void purchase()
{
registerEvent(new BookPurchasedEvent(id));
}
// getters omitted for brevity
}
服务:
@Service
@Transactional
public class BookService
{
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository)
{
this.bookRepository = bookRepository;
}
public void purchaseBook(Integer bookId)
{
Book book = bookRepository.findById(bookId)
.orElseThrow(NoSuchElementException::new);
book.purchase();
bookRepository.save(book);
}
}
听众:
@Service
public class EventListener
{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@TransactionalEventListener
public void handleEvent(BookPurchasedEvent event)
{
logger.info("Received event {}", event);
}
}
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class BookEventsTest
{
@Autowired
private BookService bookService;
@Autowired
private EntityManager entityManager;
@Test
public void test()
{
Book book = new Book("abcd-efgh", "El Quijote");
book = entityManager.merge(book);
bookService.purchaseBook(book.getId());
}
}
来自侦听器的日志消息未被记录。虽然它在部署为 REST 服务并被调用时有效,例如通过邮递员
知道了。由于我的测试是用@Transactional 注释的,因此包装测试方法的事务将被回滚。因此,不会调用带有 @TransactionalEventListener 注释的方法,因为默认情况下它会在 TransactionPhase.AFTER_COMMIT 阶段触发(除非交易成功,否则我对调用它不感兴趣)。所以测试的工作版本如下所示:
@RunWith(SpringRunner.class)
@SpringBootTest
public class BookEventsTest
{
@Autowired
private BookService bookService;
@Autowired
private BookRepository bookRepository;
@MockBean
private EventListener eventListener;
private Book book;
@Before
public void init() {
book = bookRepository.save(new Book("abcd-efgh", "El Quijote"));
}
@After
public void clean() {
bookRepository.deleteAll();
}
@Test
public void testService()
{
bookService.purchaseBook(book.getId());
then(eventListener)
.should()
.handleEvent(any(BookPurchasedEvent.class));
}
}