问题
My question is how I can change the processing order between an @EventHandler
and an @EventSourcingHandler
, for the same given Event. I have the @EventSourcinHandler
method in an Aggregate class and an @EventHandler
in an external class. If i fire an command which results in said event event, my code will run like this:
@EventSourcingHandler
@EventHandler
I want to change this order to this:
@EventHandler
@EventSourcingHandler
I tried the @Order
and @ProcessingGroup
annotations, but none of these worked for me in regards to adjusting the order.
Here is my Aggregate implementation:
@Aggregate
@Getter
@Setter
@NoArgsConstructor
@Order(2)
@ProcessingGroup("template")
@Component
public class TemplateAggregate {
private static final transient Logger logger = LoggerFactory.getLogger(TemplateAggregate.class);
@AggregateIdentifier
private String templateId;
private LocalDate createdAt;
private String createdBy;
private String description;
private LocalDate modifiedAt;
private String modifiedBy;
private String name;
private LocalDate validFrom;
private LocalDate validTo;
private File file;
private String fileName;
private long fileSize;
private LocalDate fileDate;
private String fileUploader;
@CommandHandler
public TemplateAggregate(CreateTemplateCommand cmd) {
AggregateLifecycle.apply(new TemplateCreatedEvent(cmd));
}
@CommandHandler
public void handle(ModifyTemplateCommand cmd) {
AggregateLifecycle.apply(new TemplateModifiedEvent(cmd));
}
@EventSourcingHandler
public void on(TemplateCreatedEvent event) {
this.templateId = event.getTemplateId();
this.createdAt = event.getCreatedAt();
this.createdBy = event.getCreatedBy();
this.description = event.getDescription();
this.name = event.getName();
this.validFrom = event.getValidFrom();
this.validTo = event.getValidTo();
this.file = event.getFile();
this.fileName = event.getFileName();
this.fileSize = event.getFileSize();
this.fileDate = event.getFileDate();
this.fileUploader = event.getFileUploader();
logger.info("TemplateAggregate - TemplateCreatedEvent");
}
@EventSourcingHandler
public void on(TemplateModifiedEvent event) {
this.templateId = event.getTemplateId();
this.createdAt = event.getCreatedAt();
this.createdBy = event.getCreatedBy();
this.description = event.getDescription();
this.name = event.getName();
this.validFrom = event.getValidFrom();
this.validTo = event.getValidTo();
this.file = event.getFile();
this.fileName = event.getFileName();
this.fileSize = event.getFileSize();
this.fileDate = event.getFileDate();
this.fileUploader = event.getFileUploader();
this.modifiedAt = event.getModifiedAt();
this.modifiedBy = event.getModifiedBy();
logger.info("TemplateAggregate - TemplateModifiedEvent");
}
}
My External EventHandler class:
@Service
@Order(1)
@ProcessingGroup("template")
@Component
public class TemplateCreatedEventHandler {
private static final transient Logger logger =
LoggerFactory.getLogger(TemplateCreatedEventHandler.class);
@Autowired
private TemplateRepository templateRepository;
@Transactional
@EventHandler
public void on(TemplateCreatedEvent event) {
templateRepository.save(new TemplateQueryEntity(event));
logger.info("EventHandler - TemplateCreatedEvent");
}
}
I want to do this, because I want to first persist everything in my database, so during this if i get an exception, Axon could not persist in the domain_event_entry
table.
回答1:
The @EventSourcingHandler
is used for Event Sourcing purposes. It updates the state of your aggregate at two distinct moments: when the event is first applied, in which case it is invoked immediately as part of the apply()
method, and secondly when the aggregate state is reconstructed based on its events.
That means the @EventSourcingHandler
within an Aggregate will always be invoked before any external event handlers are able to receive the event. This is not something you can change, and quite frankly, I'm sure that's also not what you want.
You mention that you want to be sure that you "want to first persist everything in my database". If you want to work in an event-driven way, this is the first principle to "let go". The primary truth is your events. You'd want to persist these first. Then, as a result of these events, you update the other tables, which feed views, generate other side-effects, etc.
If for whatever reason, you do want to ensure transactional update of your View models and your events, you can assign the Processing Group that contains your external event handler to a Subscribing Processor. This gives you the ability to invoke the Event Handler in the same transaction that also handles the Command (and publishes the events).
Also, I noticed that your aggregate contains a lot of fields. Generally, an Aggregate only needs to contains the fields that are actually used to make decisions on incoming commands. Getters (and Setters, for that matter) on Aggregate Roots in Command Models are generally a design-smell, as they shouldn't need to focus on exposing information at all.
The @Order
, @ProcessingGroup
and @Component
annotations on your aggregate have no purpose, and can be removed.
来源:https://stackoverflow.com/questions/57850894/axon-framework-change-processing-order-between-eventhandler-and-eventsourcing