Spring实现的发布者与订阅者 是观察者设计模式的一个扩展。
观察者设计模式
目标
观察者
事件
三者之间是耦合在一起的,目标里面包含观察者的集合,观察者需要自己注入到目标中,当目标发生变化的时候,则会通知观察者集合,完成不同观察者的操作
发布者与订阅者的设计模式
发布者 订阅者 事件 事件通道
使用事件通道进行解决耦合的问题
Spring默认带有这个发布者关系
发布者 ApplicationContext
订阅者:@EventListener ApplicationEventListener
事件:ApplicationEvent
通道:ApplicationEventMulticaster
一个使用Spring的demo
package designpattern.publisherandsubscribe;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class Test {
public static void main(String[] args){
ApplicationContext context=new AnnotationConfigApplicationContext(Test.class);
Test app=context.getBean(Test.class);
RegisterService registerService=(RegisterService)context.getBean(RegisterService.class);
registerService.regiesterUser();
}
}
package designpattern.publisherandsubscribe;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
@Configuration
public class AsyncEventConfig {
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster
= new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
}
package designpattern.publisherandsubscribe;
public interface EmailService {
void sendEmail();
}
package designpattern.publisherandsubscribe;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
@Service
public class EmailServiceImpl implements EmailService {
@Override
public void sendEmail() {
System.out.println("send email");
}
@EventListener
public void receiveTradeEvent(TradeEvent tradeEvent){
OrderModel orderModel=tradeEvent.getEventData();
System.out.println(orderModel.getOrderId()+"--"+orderModel.getCreateTime());
System.out.println(Thread.currentThread().getId()+"--"+Thread.currentThread().getName());
this.sendEmail();
}
}
package designpattern.publisherandsubscribe;
public interface MobileService {
String sendTelephone();
}
package designpattern.publisherandsubscribe;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Service
public class MobileServiceImpl implements MobileService {
@Override
public String sendTelephone() {
System.out.println("发短信");
return null;
}
@EventListener
public void receiveTradeEvent(TradeEvent tradeEvent){
OrderModel orderModel=tradeEvent.getEventData();
System.out.println(orderModel.getOrderId()+"--"+orderModel.getCreateTime());
System.out.println(Thread.currentThread().getId()+"--"+Thread.currentThread().getName());
this.sendTelephone();
}
}
package designpattern.publisherandsubscribe;
import java.util.Date;
public class OrderModel {
private String orderId;
private Date createTime;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
package designpattern.publisherandsubscribe;
public interface RegisterService {
public void regiesterUser();
}
package designpattern.publisherandsubscribe;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Service
public class RegisterServiceImpl implements RegisterService, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
@Transactional
public void regiesterUser() {
System.out.println("register user info to DB");
OrderModel orderModel=new OrderModel();
orderModel.setOrderId("111");
orderModel.setCreateTime(new Date());
applicationContext.publishEvent(new TradeEvent(orderModel));
System.out.println(Thread.currentThread().getId()+"--"+Thread.currentThread().getName());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
}
package designpattern.publisherandsubscribe;
import org.springframework.context.ApplicationEvent;
public class TradeEvent extends ApplicationEvent {
private T eventData;
public TradeEvent(T source) {
super(source);
this.eventData=source;
}
public T getEventData() {
return eventData;
}
public void setEventData(T eventData) {
this.eventData = eventData;
}
}
第二种发布者与订阅者的实现:分布式环境下的 消息中间件的使用,可以完成发布者和订阅者之间的关系,开源的产品notify,metaq,rocketmq,kafka。这些中间件还有一些其它的能力,比如发送消息和订阅消息,削峰填谷的能力,队列
第三种就是zookeeper的能力,也有发布订阅的能力。一个简单的case就是 如何实现DB热替换ip不宕机的需求
那就需要把配置文件的信息存储到 zookeeper的集群中,然后应用读取配置文件从zookeeper中读取,然后访问DB。应用程序需要启动zooker的客户端,连接zookeeper的服务端。
zookeeper还可以完成分布式锁,发布者和订阅者,领导选举等一些分布式的特性