@TransactionalEventListener中未调用@TransactionalEventListener注释方法

时间:2019-02-15 15:18:54

标签: spring-data-jpa domain-events

我正在尝试通过以下文章中提到的示例从实体实施域事件发布:

Example for @DomainEvents and @AfterDomainEventsPublication

但是我没有设法让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服务并调用例如通过邮递员

1 个答案:

答案 0 :(得分:0)

知道了。由于我的测试是用@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));
    }
}