Java 使用Axon 4从AMQP接收事件
我试图通过rabbitmq将消息发送到基于axon4 spring引导的系统。已收到消息,但未触发任何事件。我很确定我遗漏了一个重要的部分,但到目前为止我还没有弄清楚 这里是我申请的相关部分。ymlJava 使用Axon 4从AMQP接收事件,java,spring-boot,rabbitmq,amqp,axon,Java,Spring Boot,Rabbitmq,Amqp,Axon,我试图通过rabbitmq将消息发送到基于axon4 spring引导的系统。已收到消息,但未触发任何事件。我很确定我遗漏了一个重要的部分,但到目前为止我还没有弄清楚 这里是我申请的相关部分。yml axon: amqp: exchange: axon.fanout transaction-mode: publisher_ack # adding the following lines changed nothing eventhandli
axon:
amqp:
exchange: axon.fanout
transaction-mode: publisher_ack
# adding the following lines changed nothing
eventhandling:
processors:
amqpEvents:
source: in.queue
mode: subscribing
spring:
rabbitmq:
username: rabbit
password: rabbit
从文档中,我发现我应该创建一个SpringAMQpMessageSourcebean:
导入com.rabbitmq.client.Channel;
导入lombok.extern.slf4j.slf4j;
导入org.axonframework.extensions.amqp.eventhandling.AMQPMessageConverter;
导入org.axonframework.extensions.amqp.eventhandling.spring.SpringAMQPMessageSource;
导入org.springframework.amqp.core.Message;
导入org.springframework.amqp.rabbit.annotation.RabbitListener;
导入org.springframework.context.annotation.Bean;
导入org.springframework.context.annotation.Configuration;
@Slf4j
@配置
公共类Axonfig{
@豆子
SpringAMQPMessageSource输入消息源(最终AMQPMessageConverter消息转换器){
返回新的SpringAMQPMessageSource(messageConverter){
@RabbitListener(queues=“in.queue”)
@凌驾
公共消息无效(最终消息消息、最终通道){
调试(“收到的外部消息:{},通道:{}”,消息,通道);
super.onMessage(消息、频道);
}
};
}
}
如果我从rabbitmq管理面板向队列发送消息,我会看到以下日志:
axonfig:收到的外部消息:(正文:'[B@13f7aeef(字节[167])'MessageProperties[headers={},contentLength=0,receivedDeliveryMode=NON_PERSISTENT,Redelived=false,receivedExchange=,ReceiveDrootingKey=in.queue,deliveryTag=2,consumerTag=amq.ctag-xi34jwHHA_uXJensteX5DW,consumerQueue=in.queue]),通道:缓存的兔子通道:AMQChannel(amqp://rabbit@127.0.0.1:5672/,1),康涅狄格州:Proxy@11703cc8共享兔子连接:SimpleConnection@581cb879[代表=amqp://rabbit@127.0.0.1:5672/,localPort=58614]
此处是应接收事件的聚合:
导入lombok.extern.slf4j.slf4j;
导入org.axonframework.commandhandling.CommandHandler;
导入org.axonframework.config.ProcessingGroup;
导入org.axonframework.eventsourcing.EventSourcingHandler;
导入org.axonframework.modeling.command.AggregateIdentifier;
导入org.axonframework.spring.stereotype.Aggregate;
导入pm.mbo.easyway.api.app.order.commands.ConfirmOrderCommand;
导入pm.mbo.easyway.api.app.order.commands.PlaceOrderCommand;
导入pm.mbo.easyway.api.app.order.commands.ShipOrderCommand;
导入pm.mbo.easyway.api.app.order.events.OrderConfirmedEvent;
导入pm.mbo.easyway.api.app.order.events.OrderPlacedEvent;
导入pm.mbo.easyway.api.app.order.events.OrderShippedEvent;
导入静态org.axonframework.modeling.command.AggregateLifecycle.apply;
@ProcessingGroup(“amqpEvents”)
@Slf4j
@聚合
公共类OrderAggregate{
@聚合标识符
私有字符串orderId;
私有布尔序;
@命令处理程序
public OrderAggregate(最终PlaceOrderCommand命令){
debug(“命令:{}”,command);
应用(新的OrderPlacedEvent(command.getOrderId(),command.getProduct());
}
@命令处理程序
公共无效句柄(最终确认命令命令){
debug(“命令:{}”,command);
应用(新订单确认文件(订单ID));
}
@命令处理程序
公共无效句柄(最终ShipOrderCommand){
debug(“命令:{}”,command);
如果(!订单已确认){
抛出新的IllegalStateException(“无法发送尚未确认的订单”);
}
应用(新订单ShippedEvent(订单ID));
}
@EventSourcingHandler
在(最终OrderPlacedEvent事件)上公开作废{
调试(“事件:{}”,事件);
this.orderId=event.getOrderId();
orderconfirm=false;
}
@EventSourcingHandler
在(最终订单确认事件)上公开作废{
调试(“事件:{}”,事件);
orderconfirm=true;
}
@EventSourcingHandler
公共无效(最终订单ShippedEvent事件){
调试(“事件:{}”,事件);
orderconfirm=true;
}
受保护的OrderAggregate(){
}
}
因此,问题是系统接收到消息,但没有触发任何事件。消息的内容似乎不相关。无论我向队列发送什么,我都只从onMessage方法获得一条日志消息
SpringAMQPMessageSource的JavaDoc说:
/**
* MessageListener implementation that deserializes incoming messages and forwards them to one or more event processors.
* <p>
* The SpringAMQPMessageSource must be registered with a Spring MessageListenerContainer and forwards each message
* to all subscribed processors.
* <p>
* Note that the Processors must be subscribed before the MessageListenerContainer is started. Otherwise, messages will
* be consumed from the AMQP Queue without any processor processing them.
*
* @author Allard Buijze
* @since 3.0
*/
所以问题是,如何正确注册事件处理器。有没有一种方法可以用spring正确注册?
更新2:
这方面也不走运:
@Slf4j
@Component("rabbitMQSpringAMQPMessageSource")
public class RabbitMQSpringAMQPMessageSource extends SpringAMQPMessageSource {
@Autowired
public RabbitMQSpringAMQPMessageSource(final AMQPMessageConverter messageConverter) {
super(messageConverter);
}
@RabbitListener(queues = "${application.queues.in}")
@Override
public void onMessage(final Message message, final Channel channel) {
try {
final var eventProcessorsField = this.getClass().getSuperclass().getDeclaredField("eventProcessors");
eventProcessorsField.setAccessible(true);
final var eventProcessors = (List<Consumer<List<? extends EventMessage<?>>>>) eventProcessorsField.get(this);
log.debug("eventProcessors: {}", eventProcessors);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
log.debug("received message: message={}, channel={}", message, channel);
super.onMessage(message, channel);
}
}
除上述内容外,以编程方式注册也没有帮助:
@Autowired
void configure(EventProcessingModule epm,
RabbitMQSpringAMQPMessageSource rabbitMessageSource) {
epm.registerSubscribingEventProcessor("rabbitMQSpringAMQPMessageSource", c -> rabbitMessageSource);
epm.assignProcessingGroup("amqpEvents", "rabbitMQSpringAMQPMessageSource");// this line also made no difference
}
当然@ProcessingGroup(“amqpEvents”)在我的类中已经就位,该类包含@EventSourcingHandler注释的方法
更新25.4.19: 请参阅Allard接受的答案。非常感谢您指出我犯的错误:我错过了EventSourcingHandler不接收来自外部的消息。这是用于预测的。不是用于分发聚合!ups 下面是现在从rabbitmq接收事件的配置/类:
在Axon中,聚合不接收来自“外部”的事件。聚合内部的事件处理程序(更具体地说,它们是EventSourcingHandler)只处理由同一聚合实例发布的事件,以便它可以重建其先前的状态 只有外部事件处理程序(例如更新投影的处理程序)才会从外部源接收事件 为了实现这一点,application.yml应该将bean名称作为处理器的源而不是队列名称
eventhandling:
processors:
amqpEvents:
source: in.queue
mode: subscribing
应成为:
eventhandling:
processors:
amqpEvents:
source: inputMessageSource
mode: subscribing
但同样,这只适用于在组件上定义的事件处理程序,而不适用于聚合。Thx Allard!这很有帮助
@Autowired
void configure(EventProcessingModule epm,
RabbitMQSpringAMQPMessageSource rabbitMessageSource) {
epm.registerSubscribingEventProcessor("rabbitMQSpringAMQPMessageSource", c -> rabbitMessageSource);
epm.assignProcessingGroup("amqpEvents", "rabbitMQSpringAMQPMessageSource");// this line also made no difference
}
axon:
eventhandling:
processors:
amqpEvents:
source: rabbitMQSpringAMQPMessageSource
mode: SUBSCRIBING
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.extensions.amqp.eventhandling.AMQPMessageConverter;
import org.axonframework.extensions.amqp.eventhandling.spring.SpringAMQPMessageSource;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component("rabbitMQSpringAMQPMessageSource")
public class RabbitMQSpringAMQPMessageSource extends SpringAMQPMessageSource {
@Autowired
public RabbitMQSpringAMQPMessageSource(final AMQPMessageConverter messageConverter) {
super(messageConverter);
}
@RabbitListener(queues = "${application.queues.in}")
@Override
public void onMessage(final Message message, final Channel channel) {
log.debug("received message: message={}, channel={}", message, channel);
super.onMessage(message, channel);
}
}
import lombok.extern.slf4j.Slf4j;
import org.axonframework.config.ProcessingGroup;
import org.axonframework.eventhandling.EventHandler;
import org.axonframework.queryhandling.QueryHandler;
import org.springframework.stereotype.Service;
import pm.mbo.easyway.api.app.order.events.OrderConfirmedEvent;
import pm.mbo.easyway.api.app.order.events.OrderPlacedEvent;
import pm.mbo.easyway.api.app.order.events.OrderShippedEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@ProcessingGroup("amqpEvents")
@Service
public class OrderedProductsEventHandler {
private final Map<String, OrderedProduct> orderedProducts = new HashMap<>();
@EventHandler
public void on(OrderPlacedEvent event) {
log.debug("event: {}", event);
String orderId = event.getOrderId();
orderedProducts.put(orderId, new OrderedProduct(orderId, event.getProduct()));
}
@EventHandler
public void on(OrderConfirmedEvent event) {
log.debug("event: {}", event);
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.setOrderConfirmed();
return orderedProduct;
});
}
@EventHandler
public void on(OrderShippedEvent event) {
log.debug("event: {}", event);
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.setOrderShipped();
return orderedProduct;
});
}
@QueryHandler
public List<OrderedProduct> handle(FindAllOrderedProductsQuery query) {
log.debug("query: {}", query);
return new ArrayList<>(orderedProducts.values());
}
}
RabbitMQSpringAMQPMessageSource : received message: ...
OrderedProductsEventHandler : event: OrderShippedEvent...
eventhandling:
processors:
amqpEvents:
source: in.queue
mode: subscribing
eventhandling:
processors:
amqpEvents:
source: inputMessageSource
mode: subscribing