如何使用Spring3.x事件源码案例
创建松耦合的应用程序有很多的概念和技术,事件就是其中之一。事件可以消除许多在你的代码中的依赖关系。在java中Observer接口可以帮助我们实现事件(通过Observer模式)。
想象一下,一个简单的应用程序,这些要求:
有一些指令,可以有不同的状态
当一个订单交付或推迟状态,我们需要发送电子邮件给客户
第一(但不是最好的)解决方案是在我们的订单模型中直接发送电子邮件,但是,也有一些缺陷:
- 这个类不是负责订单发送电子邮件的,违背单一职责。
- 如果你遵循领域驱动的原则,订单是一个领域对象,但,电子邮件发件人也许是一种服务(不同于领域服务),所以你不能用它在你的模型中。
订单代码如下
@Configurable
public class Order implements ApplicationEventPublisherAware {
private final String orderId;
private final Date createDate;
private final CustomerInfo customerInfo;
private ApplicationEventPublisher eventPublisher;
private Date lastUpdateDate;
private Status status;
public Order(String orderId, CustomerInfo customerInfo) {
this.orderId = orderId;
this.customerInfo = customerInfo;
status = Status.MODIFIABLE;
this.createDate = new Date();
this.lastUpdateDate = this.createDate;
}
public String getOrderId() {
return orderId;
}
public void checkOut() {
if (status == Status.DELIVERED) {
throw new IllegalStateException(String.format("Order is already delivered"));
}
this.status = Status.CHECKED_OUT;
this.lastUpdateDate = new Date();
}
public void deliver() {
if (this.status != Status.CHECKED_OUT && this.status != Status.POSTPONED) {
throw new IllegalStateException(String.format("Order status should be CHECKED OUT for delivery to be called. but is : %s", status));
}
this.status = Status.DELIVERED;
this.lastUpdateDate = new Date();
this.eventPublisher.publishEvent(new OnOrderDelivered(this));
}
public void postponeDelivery() {
if (status != Status.CHECKED_OUT && status != Status.POSTPONED) {
throw new IllegalStateException(String.format("Can not postpone delivery in this state: %s", status));
}
this.status = Status.POSTPONED;
this.lastUpdateDate = new Date();
this.eventPublisher.publishEvent(new OnOrderPostponed(this));
}
public Status getStatus() {
return status;
}
public CustomerInfo getCustomerInfo() {
return customerInfo;
}
public Date getLastUpdateDate() {
return lastUpdateDate;
}
public Date getCreateDate() {
return createDate;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
public static enum Status {
MODIFIABLE,
CHECKED_OUT,
POSTPONED,
DELIVERED,
CANCELED;
}
}
Order类实现org.springframework.context.ApplicationEventPublisherAware接口。这个接口有一个setter方法名称为setApplicationEventPublisher,用来设置ApplicationEventPublisher的。,我们使用这个对象来发布一个事件this.eventPublisher.publishEvent。发布每个事件是继承org.springframework.context.ApplicationEvent
public abstract class OnOrderStatusChanged extends ApplicationEvent {
private final Order order;
public OnOrderStatusChanged(Order source) {
super(source);
this.order = source;
System.out.println(String.format("Order:%s status is changed to %s", source.getOrderId(), source.getStatus()));
}
public Order getOrder() {
return order;
}
}
public class OnOrderDelivered extends OnOrderStatusChanged {
public OnOrderDelivered(Order order) {
super(order);
}
}
public class OnOrderPostponed extends OnOrderStatusChanged {
public OnOrderPostponed(Order order) {
super(order);
}
}
下面是事件的监听者,同时实现邮件发送:
@Service
public class OrderDeliveredEmailSender implements ApplicationListener,Ordered {
@Override
public void onApplicationEvent(OnOrderDelivered event) {
System.out.println(String.format("Message sent for delivered order to:%s ORDER-ID:%s",event.getOrder().getCustomerInfo().getEmail(),event.getOrder().getOrderId()));
}
@Override
public int getOrder() {
return 100;
}
}
@Service
public class OrderPostponedEmailSender implements ApplicationListener {
@Override
public void onApplicationEvent(OnOrderPostponed event) {
System.out.println(String.format("Message sent for postponed order to:%s ORDER-ID:%s", event.getOrder().getCustomerInfo().getEmail(), event.getOrder().getOrderId()));
}
}
onApplicationEvent引发两个对应事件。对于监听发布产品的客户,我们需要创建另一个监听OnOrderDelivered事件。
@Service
public class OnOrderDeliveredPost implements ApplicationListener,Ordered {
@Override
public void onApplicationEvent(OnOrderDelivered onOrderDelivered) {
System.out.println(String.format("Order:%s is posting for customer.",onOrderDelivered.getOrder().getOrderId()));
}
@Override
public int getOrder() {
return 1000;
}
}