このブログとこの参考資料を読み、Spring Data Commons ドメイン イベントは、Spring Data REST AbstractRepositoryEventListener イベント (つまり、onBeforeSave、onAfterDelete など) 内に適用すると機能しないと判断しました。
人:
@Entity @Data @EqualsAndHashCode(callSuper=true)
public class Person extends AbstractEntity {
// impl
public void markComplete(){
registerEvent(new PersonCompletedEvent());
}
}
PersonCompletedEvent:
@Data public class PersonCompletedEvent {} // the RestBucks sample does not have OrderPaid event extend ApplicationEvent, I tried both ways and it still doesn't work.
更新: PersonHandler のコメントを読んでください。これが、この例でアプリケーション イベントが機能しない理由です。
PersonHandler:
@Component @RepositoryEventHandler public class PersonHandler {
@PersistenceContext private EntityManager entityManager;
@Autowired private PersonRepo personRepo;
@HandleBeforeSave public void beforeSave(Person afterPerson){
/* UPDATE ::: This is the problem.
* This line is the reason why applicatin events do not fire.
* I need the before entity to detect delta's in the domain
* so I must detach it. However this causes events to be dropped.
*
* What's the best way to get the previous state?
*/
entityManager.detach(afterPerson);
Person beforePerson = personRepo.findOne(afterPerson.getId());
// impl
if (some condition) {
afterPerson.markComplete(); // this does add the event but it's never fired.
}
}
}
抽象エンティティ:
import org.springframework.data.domain.AbstractAggregateRoot;
@MappedSuperclass @Data @EntityListeners(AuditingEntityListener.class)
public abstract class AbstractEntity extends AbstractAggregateRoot implements Identifiable<Long> {
// impl
}
パーソンリスナー:
public class PersonListener {
@EventListener
public void processCompleted(PersonCompletedEvent event) {
// THIS IS NEVER FIRED
}
}
これを広範囲にデバッグしましたが、 DomainEvents がRepositoryEntityControllerとEventPublishingRepositoryProxyPostProcessor$EventPublishingMethodInterceptorの間のどこかにドロップされているようです。
実際に起こっていることは、エンティティの別のインスタンスが実際に傍受されており、その時点で DomainEvents が存在しなくなっていることです。@AfterDomainEventPublication clearDomainEvents() が現時点で呼び出されていないことを確認できます。これにより、一時的な domainEvents と関係があると思われます。
Spring Data REST のRepositoryEntityControllerは次のようになります。
private ResponseEntity<ResourceSupport> saveAndReturn(Object domainObject, RepositoryInvoker invoker,
HttpMethod httpMethod, PersistentEntityResourceAssembler assembler, boolean returnBody) {
publisher.publishEvent(new BeforeSaveEvent(domainObject)); // 1
Object obj = invoker.invokeSave(domainObject); // 2
publisher.publishEvent(new AfterSaveEvent(obj));
1 でコメントされた行を実行した後、私の domainObject には domainEvents があり、それが 2 でコメントされた行、invokeSave に入ります。ブレークポイントがRepositoryEntityControllerとEventPublishingRepositoryProxyPostProcessor$EventPublishingMethodInterceptorでキャッチされると、実際にはオブジェクトの別のインスタンス (別のオブジェクト ID) であり、欠けているのは domainEvents だけで、何も発生しません。
更新: 以下の私のコメントを読んでください。エンティティが切り離されているため、機能していません。