设计模式——观察者模式(三)Google Guava EventBus

Google Guava 事件总线 

传统上,Java的进程内事件分发都是通过发布者和订阅者之间的显式注册实现的。设计EventBus就是为了取代这种显示注册方式,使组件间有了更好的解耦。EventBus不是通用型的发布-订阅实现,不适用于进程间通信。

 EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式,EventBus非常优雅使用起来也非常的简单,这个可不是吹的是真的非常的简单。

依赖

         
            com.google.guava
            guava
            20.0
        

 EventBus的使用

package org.demo.spring.event.eventbus;

import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionContext;
import com.google.common.eventbus.SubscriberExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 事件总线工厂
 * 
 */
@Slf4j
public class EventBusFactory {

    // 同步事件总线
    private volatile static EventBus eventBus;
    // 异步事件总线
    private volatile static AsyncEventBus asyncEventBus;

    private static ThreadPoolExecutor threadPoolExecutor;

    /**
     * 默认使用异步事件总线
     * @return
     */
    public static EventBus getEventBus() {
        return  getEventBus(true);
    }

    /**
     *  可以采用静态内部类实现单例
     */
    public static EventBus getEventBus(boolean async) {
        if (async) {
            if (asyncEventBus == null) {
                synchronized (AsyncEventBus.class) {
                    // 双重检查,避免并发访问创建多个对象问题
                    if (asyncEventBus == null) {
                        asyncEventBus = new AsyncEventBus(getEventBusThreadPool());
                    }
                }
            }

            return asyncEventBus;
        } else {
            if (eventBus == null) {
                synchronized (EventBus.class) {
                    // 双重检查,避免并发访问创建多个对象问题
                    if (eventBus == null) {
                        eventBus = new EventBus(DefaultExceptionHandler.INSTANCE);
                    }
                }
            }
            return eventBus;
        }
    }


    private static ThreadPoolExecutor getEventBusThreadPool() {
        if (threadPoolExecutor == null) {
            // 当队列满时,任务直接丢弃,避免出错
            threadPoolExecutor = new ThreadPoolExecutor(20,
                    120,
                    60,
                    TimeUnit.SECONDS,
                    new LinkedBlockingDeque<>(100000),
                    new NamedThreadFactory("EventBus_BlockThreadPool"),
                    new ThreadPoolExecutor.DiscardPolicy());
        }
        return threadPoolExecutor;
    }

    /**
     * 默认异常处理者
     * 
     */
    static class DefaultExceptionHandler implements SubscriberExceptionHandler {

        public static final DefaultExceptionHandler INSTANCE  = new DefaultExceptionHandler();
        // 是否有错
        private ThreadLocal                errorFlag = new ThreadLocal() {

                                                                  @Override
                                                                  protected Boolean initialValue() {
                                                                      return false;
                                                                  }
                                                              };

        @Override
        public void handleException(Throwable exception, SubscriberExceptionContext context) {
            if (!errorFlag.get()) {
                errorFlag.set(true);
            }
            Logger logger = logger(context);
            logger.error(message(context), exception);
        }

        public boolean hasError() {
            return errorFlag.get();
        }

        public void clearErrorFlag() {
            errorFlag.remove();
        }

        private static Logger logger(SubscriberExceptionContext context) {
            return LoggerFactory.getLogger(DefaultExceptionHandler.class);
        }

        private static String message(SubscriberExceptionContext context) {
            Method method = context.getSubscriberMethod();
            return "Exception thrown by subscriber method " + method.getName() + '('
                   + method.getParameterTypes()[0].getName() + ')' + " on subscriber " + context.getSubscriber()
                   + " when dispatching event: " + context.getEvent();
        }
    }

    /**
     * 返回并执行删除
     * @return true 表示有错误,false表示没有错误
     */
    public static boolean getAndRemoveErrorFlag() {
        try {
           return DefaultExceptionHandler.INSTANCE.hasError();
        } finally {
            DefaultExceptionHandler.INSTANCE.clearErrorFlag();
        }
    }
}
package org.demo.spring.event.eventbus;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 复制来源 org.apache.dubbo.common.utils -NamedThreadFactory
 */
public class NamedThreadFactory implements ThreadFactory {
    protected static final AtomicInteger POOL_SEQ = new AtomicInteger(1);
    protected final AtomicInteger mThreadNum;
    protected final String mPrefix;
    protected final boolean mDaemon;
    protected final ThreadGroup mGroup;

    public NamedThreadFactory() {
        this("pool-" + POOL_SEQ.getAndIncrement(), false);
    }

    public NamedThreadFactory(String prefix) {
        this(prefix, false);
    }

    public NamedThreadFactory(String prefix, boolean daemon) {
        this.mThreadNum = new AtomicInteger(1);
        this.mPrefix = prefix + "-thread-";
        this.mDaemon = daemon;
        SecurityManager s = System.getSecurityManager();
        this.mGroup = s == null ? Thread.currentThread().getThreadGroup() : s.getThreadGroup();
    }

    public Thread newThread(Runnable runnable) {
        String name = this.mPrefix + this.mThreadNum.getAndIncrement();
        Thread ret = new Thread(this.mGroup, runnable, name, 0L);
        ret.setDaemon(this.mDaemon);
        return ret;
    }

    public ThreadGroup getThreadGroup() {
        return this.mGroup;
    }
}
/**
 * 事件
 *
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class IEvent implements Serializable {
    private static final long serialVersionUID = -8819029849121087074L;

    private Map map;

}
/**
 * 事件监听器
 */
@Component
@Slf4j
public class IEventListener {

    @PostConstruct
    private void init() {
        // 注册事件监听器
        EventBusFactory.getEventBus().register(this);
    }

    @Subscribe
    @AllowConcurrentEvents
    public final void listen(IEvent iEvent) {
        log.info("接受订阅消息:{}", iEvent);
    }


}

测试:

/**
 * 事件发布测试
 *  由于是自己搭建的springboot项目,启动非常快,有时测试就直接用定时任务,不写单侧了
 */
@Component
public class TestJob {

    @Scheduled(cron = "*/5 * * * * ?")
    public void cronJob() {
        IEvent iEvent = new IEvent();
        Map map = new HashMap() {
            {
                put("a", "123");
                put("b", "456");
            }
        };
        iEvent.setMap(map);
        EventBusFactory.getEventBus().post(iEvent);

    }

}

参考:


Google Guava EventBus

Google Guava]-事件总线

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