设计模式--发布者与订阅者

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还可以完成分布式锁,发布者和订阅者,领导选举等一些分布式的特性

你可能感兴趣的:(设计模式)