通过AOP在所有应用服务方法前监听领域事件
package org.infinite.framework.ddd.event;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.infinite.framework.ddd.domain.model.DomainEvent;
import org.infinite.framework.ddd.domain.model.DomainEventPublisher;
import org.infinite.framework.ddd.domain.model.DomainEventSubscriber;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 存储所有的领域事件
*
* @author Darkness
* @date 2014-5-5 下午5:19:56
* @version V1.0
*/
@Aspect
public class DomainEventStoreProcessor {
@Autowired
private EventStore eventStore;
/**
* Registers a DomainEventStoreProcessor to listen
* and forward all domain events to external subscribers.
* This factory method is provided in the case where
* Spring AOP wiring is not desired.
*/
public static void register() {
(new DomainEventStoreProcessor()).listen();
}
/**
* Constructs my default state.
*/
public DomainEventStoreProcessor() {
super();
}
/**
* Listens for all domain events and stores them.
*/
@Before("execution(* org.infinite..application..*Service.*(..))")
public void listen() {
DomainEventPublisher
.instance()
.subscribe(new DomainEventSubscriber<DomainEvent>() {
public void handleEvent(DomainEvent aDomainEvent) {
store(aDomainEvent);
}
public Class<DomainEvent> subscribedToEventType() {
return DomainEvent.class; // all domain events
}
});
}
/**
* Stores aDomainEvent to the event store.
* @param aDomainEvent the DomainEvent to store
*/
private void store(DomainEvent aDomainEvent) {
this.eventStore().append(aDomainEvent);
}
/**
* Answers my EventStore.
* @return EventStore
*/
private EventStore eventStore() {
return this.eventStore;
}
}
事件仓储负责查询&持久化领域事件
package org.infinite.framework.ddd.event;
import java.util.List;
import org.infinite.framework.ddd.domain.model.DomainEvent;
/**
* 事件存储器
*
* @author Darkness
* @date 2014-5-5 下午7:58:31
* @version V1.0
*/
public interface EventStore {
List<StoredEvent> allStoredEventsBetween(long aLowStoredEventId, long aHighStoredEventId);
List<StoredEvent> allStoredEventsSince(long aStoredEventId);
StoredEvent append(DomainEvent aDomainEvent);
void close();
long countStoredEvents();
}
存储的事件定义
package org.infinite.framework.ddd.event;
import java.util.Date;
import org.infinite.framework.ddd.domain.model.DomainEvent;
import org.infinite.framework.utility.AssertionConcern;
/**
* 存储的事件
*
* @author Darkness
* @date 2014-5-5 下午8:05:11
* @version V1.0
*/
public class StoredEvent extends AssertionConcern {
private long eventId;// 序列号
private Date occurredOn;
private String typeName;// 领域事件的实际类名
private String eventBody;// DomainEvent的序列化数据
public StoredEvent(String aTypeName, Date anOccurredOn, String anEventBody) {
this();
this.setEventBody(anEventBody);
this.setOccurredOn(anOccurredOn);
this.setTypeName(aTypeName);
}
public StoredEvent(String aTypeName, Date anOccurredOn, String anEventBody, long anEventId) {
this(aTypeName, anOccurredOn, anEventBody);
this.setEventId(anEventId);
}
public String eventBody() {
return this.eventBody;
}
public long eventId() {
return this.eventId;
}
public Date occurredOn() {
return this.occurredOn;
}
@SuppressWarnings("unchecked")
public <T extends DomainEvent> T toDomainEvent() {
Class<T> domainEventClass = null;
try {
domainEventClass = (Class<T>) Class.forName(this.typeName());
} catch (Exception e) {
throw new IllegalStateException("Class load error, because: " + e.getMessage());
}
T domainEvent =
EventSerializer
.instance()
.deserialize(this.eventBody(), domainEventClass);
return domainEvent;
}
public String typeName() {
return this.typeName;
}
@Override
public boolean equals(Object anObject) {
boolean equalObjects = false;
if (anObject != null && this.getClass() == anObject.getClass()) {
StoredEvent typedObject = (StoredEvent) anObject;
equalObjects = this.eventId() == typedObject.eventId();
}
return equalObjects;
}
@Override
public int hashCode() {
int hashCodeValue =
+ (1237 * 233)
+ (int) this.eventId();
return hashCodeValue;
}
@Override
public String toString() {
return "StoredEvent [eventBody=" + eventBody + ", eventId=" + eventId + ", occurredOn=" + occurredOn + ", typeName="
+ typeName + "]";
}
public StoredEvent() {
super();
this.setEventId(-1);
}
protected void setEventBody(String anEventBody) {
this.assertArgumentNotEmpty(anEventBody, "The event body is required.");
this.assertArgumentLength(anEventBody, 1, 65000, "The event body must be 65000 characters or less.");
this.eventBody = anEventBody;
}
protected void setEventId(long anEventId) {
this.eventId = anEventId;
}
protected void setOccurredOn(Date anOccurredOn) {
this.occurredOn = anOccurredOn;
}
protected void setTypeName(String aTypeName) {
this.assertArgumentNotEmpty(aTypeName, "The event type name is required.");
this.assertArgumentLength(aTypeName, 1, 100, "The event type name must be 100 characters or less.");
this.typeName = aTypeName;
}
}
事件序列化
package org.infinite.framework.ddd.event;
import org.infinite.framework.ddd.domain.model.DomainEvent;
import org.infinite.framework.ddd.serializer.AbstractSerializer;
/**
* 事件序列化处理器
*
* @author Darkness
* @date 2014-5-5 下午8:08:48
* @version V1.0
*/
public class EventSerializer extends AbstractSerializer {
private static EventSerializer eventSerializer;
public static synchronized EventSerializer instance() {
if (EventSerializer.eventSerializer == null) {
EventSerializer.eventSerializer = new EventSerializer();
}
return EventSerializer.eventSerializer;
}
private EventSerializer() {
this(false, false);
}
public EventSerializer(boolean isCompact) {
this(false, isCompact);
}
public EventSerializer(boolean isPretty, boolean isCompact) {
super(isPretty, isCompact);
}
/**
* 序列化事件
*
* @author Darkness
* @date 2014-5-5 下午8:12:33
* @version V1.0
*/
public String serialize(DomainEvent aDomainEvent) {
String serialization = this.gson().toJson(aDomainEvent);
return serialization;
}
/**
* 反序列化事件
*
* @author Darkness
* @date 2014-5-5 下午8:13:23
* @version V1.0
*/
public <T extends DomainEvent> T deserialize(String aSerialization, final Class<T> aType) {
T domainEvent = this.gson().fromJson(aSerialization, aType);
return domainEvent;
}
}
package org.infinite.framework.ddd.serializer;
import java.lang.reflect.Type;
import java.util.Date;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* 抽象序列化处理器
*
* @author Darkness
* @date 2014-5-5 下午8:09:47
* @version V1.0
*/
public class AbstractSerializer {
private Gson gson;
protected AbstractSerializer(boolean isCompact) {
this(false, isCompact);
}
protected AbstractSerializer(boolean isPretty, boolean isCompact) {
super();
if (isPretty && isCompact) {
this.buildForPrettyCompact();
} else if (isCompact) {
this.buildForCompact();
} else {
this.build();
}
}
protected Gson gson() {
return this.gson;
}
private void build() {
this.gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateSerializer())
.registerTypeAdapter(Date.class, new DateDeserializer())
.serializeNulls().create();
}
private void buildForCompact() {
this.gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateSerializer())
.registerTypeAdapter(Date.class, new DateDeserializer())
.create();
}
private void buildForPrettyCompact() {
this.gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateSerializer())
.registerTypeAdapter(Date.class, new DateDeserializer())
.setPrettyPrinting()
.create();
}
private class DateSerializer implements JsonSerializer<Date> {
public JsonElement serialize(Date source, Type typeOfSource, JsonSerializationContext context) {
return new JsonPrimitive(Long.toString(source.getTime()));
}
}
private class DateDeserializer implements JsonDeserializer<Date> {
public Date deserialize(JsonElement json, Type typeOfTarget, JsonDeserializationContext context) throws JsonParseException {
long time = Long.parseLong(json.getAsJsonPrimitive().getAsString());
return new Date(time);
}
}
}
Hibernate事件仓储实现
package org.infinite.framework.ddd.port.adapter.persistence.hibernate;
import java.util.List;
import org.hibernate.Query;
import org.infinite.framework.ddd.domain.model.DomainEvent;
import org.infinite.framework.ddd.event.EventSerializer;
import org.infinite.framework.ddd.event.EventStore;
import org.infinite.framework.ddd.event.StoredEvent;
import org.infinite.framework.persistence.CleanableStore;
import org.infinite.framework.persistence.hibernate.HibernateSessionSupport;
/**
* Hibernate事件存储器实现
*
* @author Darkness
* @date 2014-5-22 下午9:08:44
* @version V1.0
* @since ark 1.0
*/
public class HibernateEventStore
extends HibernateSessionSupport
implements EventStore, CleanableStore {
public HibernateEventStore() {
super();
}
/**
* 查询存储的事件
*/
@Override
@SuppressWarnings("unchecked")
public List<StoredEvent> allStoredEventsBetween(long aLowStoredEventId, long aHighStoredEventId) {
Query query = this.session().createQuery(
"from StoredEvent as _obj_ "
+ "where _obj_.eventId between ? and ? "
+ "order by _obj_.eventId");
query.setParameter(0, aLowStoredEventId);
query.setParameter(1, aHighStoredEventId);
List<StoredEvent> storedEvents = query.list();
return storedEvents;
}
@Override
@SuppressWarnings("unchecked")
public List<StoredEvent> allStoredEventsSince(long aStoredEventId) {
Query query =
this.session().createQuery(
"from StoredEvent as _obj_ "
+ "where _obj_.eventId > ? "
+ "order by _obj_.eventId");
query.setParameter(0, aStoredEventId);
List<StoredEvent> storedEvents = query.list();
return storedEvents;
}
@Override
public StoredEvent append(DomainEvent aDomainEvent) {
String eventSerialization = EventSerializer.instance().serialize(aDomainEvent);
StoredEvent storedEvent =
new StoredEvent(
aDomainEvent.getClass().getName(),
aDomainEvent.occurredOn(),
eventSerialization);
this.session().save(storedEvent);
return storedEvent;
}
@Override
public void close() {
// no-op
}
@Override
public long countStoredEvents() {
Query query =
this.session().createQuery("select count(*) from StoredEvent");
long count = ((Long) query.uniqueResult()).longValue();
return count;
}
@Override
public void clean() {
}
}