从领域模型中发布领域事件——轻量级领域事件发布器

领域事件

package org.infinite.framework.ddd.domain.model;

import java.util.Date;

/**
 *  领域事件
 * 
 * @author Darkness
 * @date 2014-5-5 下午4:52:14 
 * @version V1.0
 */
public interface DomainEvent {

	int eventVersion();

	/**
	 *  事件发生的时间
	 * 
	 * @author Darkness
	 * @date 2014-5-5 下午4:52:35 
	 * @version V1.0
	 */
	Date occurredOn();
}

事件发布器

package org.infinite.framework.ddd.domain.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 *  事件发布器
 * 
 * @author Darkness
 * @date 2014-5-5 下午7:30:50 
 * @version V1.0
 */
public class DomainEventPublisher {

	private static final ThreadLocal<DomainEventPublisher> instance = new ThreadLocal<DomainEventPublisher>() {
		@Override
		protected DomainEventPublisher initialValue() {
			return new DomainEventPublisher();
		}
	};

	private boolean publishing;

	// 订阅方列表
	@SuppressWarnings("rawtypes")
	private List subscribers;

	public static DomainEventPublisher instance() {
		return instance.get();
	}

	public <T> void publish(final T aDomainEvent) {
		if (!this.isPublishing() && this.hasSubscribers()) {

			try {
				this.setPublishing(true);

				Class<?> eventType = aDomainEvent.getClass();

				@SuppressWarnings("unchecked")
				List<DomainEventSubscriber<T>> allSubscribers = this.subscribers();

				for (DomainEventSubscriber<T> subscriber : allSubscribers) {
					Class<T> subscribedToType = subscriber.subscribedToEventType();

					if (eventType == subscribedToType || subscribedToType == DomainEvent.class) {
						subscriber.handleEvent(aDomainEvent);
					}
				}

			} finally {
				this.setPublishing(false);
			}
		}
	}

	public void publishAll(Collection<DomainEvent> aDomainEvents) {
		for (DomainEvent domainEvent : aDomainEvents) {
			this.publish(domainEvent);
		}
	}

	/**
	 * 清空所有监听
	 * 
	 * @author Darkness
	 * @date 2014-12-16 下午7:10:02 
	 * @version V1.0
	 */
	public void reset() {
		if (!this.isPublishing()) {
			this.setSubscribers(null);
		}
	}

	/**
	 *  注册订阅方
	 * 
	 * @author Darkness
	 * @date 2014-5-5 下午7:48:27 
	 * @version V1.0
	 */
	@SuppressWarnings("unchecked")
	public <T> void subscribe(DomainEventSubscriber<T> aSubscriber) {
		if (!this.isPublishing()) {
			this.ensureSubscribersList();

			this.subscribers().add(aSubscriber);
		}
	}

	private DomainEventPublisher() {
		super();

		this.setPublishing(false);
		this.ensureSubscribersList();
	}

	@SuppressWarnings("rawtypes")
	private void ensureSubscribersList() {
		if (!this.hasSubscribers()) {
			this.setSubscribers(new ArrayList());
		}
	}

	private boolean isPublishing() {
		return this.publishing;
	}

	private void setPublishing(boolean aFlag) {
		this.publishing = aFlag;
	}

	private boolean hasSubscribers() {
		return this.subscribers() != null;
	}

	@SuppressWarnings("rawtypes")
	private List subscribers() {
		return this.subscribers;
	}

	@SuppressWarnings("rawtypes")
	private void setSubscribers(List aSubscriberList) {
		this.subscribers = aSubscriberList;
	}
}

事件监听

package org.infinite.framework.ddd.domain.model;

/**
 * 事件监听
 * 
 * @author Darkness
 * @date 2014-12-23 下午4:53:35 
 * @version V1.0
 */
public interface DomainEventSubscriber<T> {

	void handleEvent(final T aDomainEvent);

	Class<T> subscribedToEventType();
}

轻量级领域事件发布器测试

package org.infinite.framework.ddd.event;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.infinite.framework.ddd.domain.model.DomainEventPublisher;
import org.infinite.framework.ddd.domain.model.DomainEventSubscriber;
import org.infinite.framework.ddd.event.TestableDomainEvent;
import org.junit.Before;
import org.junit.Test;

/**
 * 轻量级领域事件发布器测试
 * 
 * @author Darkness
 * @date 2014-12-23 下午4:29:52 
 * @version V1.0
 */
public class DomainEventPublisherTest {

    private boolean anotherEventHandled;
    private boolean eventHandled;

    @Before
    public void init() {
    	DomainEventPublisher.instance().reset();
    }
    
    @Test
    public void domainEventPublisherPublish() throws Exception {
        DomainEventPublisher.instance().subscribe(new DomainEventSubscriber<TestableDomainEvent>(){
            @Override
            public void handleEvent(TestableDomainEvent aDomainEvent) {
                assertEquals(100L, aDomainEvent.id());
                assertEquals("test", aDomainEvent.name());
                eventHandled = true;
            }
            @Override
            public Class<TestableDomainEvent> subscribedToEventType() {
                return TestableDomainEvent.class;
            }
        });

        assertFalse(this.eventHandled);

        DomainEventPublisher.instance().publish(new TestableDomainEvent(100L, "test"));

        assertTrue(this.eventHandled);
    }

    @Test
    public void domainEventPublisherBlocked() throws Exception {
        DomainEventPublisher.instance().subscribe(new DomainEventSubscriber<TestableDomainEvent>(){
            @Override
            public void handleEvent(TestableDomainEvent aDomainEvent) {
                assertEquals(100L, aDomainEvent.id());
                assertEquals("test", aDomainEvent.name());
                eventHandled = true;
                // 不支持嵌套发布消息
                // attempt nested publish, which should not work
                DomainEventPublisher.instance().publish(new AnotherTestableDomainEvent(1000.0));
            }
            @Override
            public Class<TestableDomainEvent> subscribedToEventType() {
                return TestableDomainEvent.class;
            }
        });

        DomainEventPublisher.instance().subscribe(new DomainEventSubscriber<AnotherTestableDomainEvent>(){
            @Override
            public void handleEvent(AnotherTestableDomainEvent aDomainEvent) {
                // should never be reached due to blocked publisher
                assertEquals(1000.0, aDomainEvent.value(), 0.0001);
                anotherEventHandled = true;
            }
            @Override
            public Class<AnotherTestableDomainEvent> subscribedToEventType() {
                return AnotherTestableDomainEvent.class;
            }
        });

        assertFalse(this.eventHandled);
        assertFalse(this.anotherEventHandled);

        DomainEventPublisher.instance().publish(new TestableDomainEvent(100L, "test"));

        assertTrue(this.eventHandled);
        assertFalse(this.anotherEventHandled);
    }
}

测试事件

package org.infinite.framework.ddd.event;

import java.util.Date;

import org.infinite.framework.ddd.domain.model.DomainEvent;


public class TestableDomainEvent implements DomainEvent {

	private long id;
    private String name;
    
    private int eventVersion;
    private Date occurredOn;

    public TestableDomainEvent(long anId, String aName) {
        super();

        this.setEventVersion(1);
        this.setId(anId);
        this.setName(aName);
        this.setOccurredOn(new Date());
    }

    public int eventVersion() {
        return eventVersion;
    }

    public long id() {
        return id;
    }

    public String name() {
        return name;
    }

    @Override
    public Date occurredOn() {
        return this.occurredOn;
    }

    private void setEventVersion(int anEventVersion) {
        this.eventVersion = anEventVersion;
    }

    private void setId(long id) {
        this.id = id;
    }

    private void setName(String name) {
        this.name = name;
    }

    private void setOccurredOn(Date occurredOn) {
        this.occurredOn = occurredOn;
    }
}

package org.infinite.framework.ddd.event;

import java.util.Date;

import org.infinite.framework.ddd.domain.model.DomainEvent;


public class AnotherTestableDomainEvent implements DomainEvent {

    private int eventVersion;
    private Date occurredOn;
    private double value;

    public AnotherTestableDomainEvent(double aValue) {
        super();

        this.setEventVersion(1);
        this.setOccurredOn(new Date());
        this.setValue(aValue);
    }

    public int eventVersion() {
        return eventVersion;
    }

    @Override
    public Date occurredOn() {
        return this.occurredOn;
    }

    public double value() {
        return this.value;
    }

    private void setEventVersion(int eventVersion) {
        this.eventVersion = eventVersion;
    }

    private void setOccurredOn(Date occurredOn) {
        this.occurredOn = occurredOn;
    }

    private void setValue(double value) {
        this.value = value;
    }
}


你可能感兴趣的:(从领域模型中发布领域事件——轻量级领域事件发布器)