事件驱动模式-Tomcat和zookeeper教你如何玩

导读:本篇文章讲解 事件驱动模式-Tomcat和zookeeper教你如何玩,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

事件驱动模式的基本原理是构件并不直接调用过程,而是触发一个或多个事件。系统中的其他构件可以注册相关的事件,触发一个事件时,系统会自动调用注册了该事件的构件过程,即触发事件会导致另一构件中过程的调用。 通常的事件驱动设计中,会涉及到事件,事件监听,事件发布接口。流程如下:

事件驱动模式-Tomcat和zookeeper教你如何玩

在tomcat容器的加载,zoomkeeper中watcher机制的实现,都是基于事件驱动实现的。另外,在常见的业务中,用户注册成功后,发送优惠券,发送短信通知的操作。用户支付成功,app消息通知,用户短信通知的操作。都会在完成某项动作,就触发一系列操作。

tomcat7中,事件驱动的实现

在tomcat中,catalina容器包含很多的组件,例如,日志记录器,session管理器,servlet类载入器等等。这些组件都是随着catalina的启动,停止而启动或停止的。catalina容器使用Lifecycle定义容器的生命周期,例如start,容器的启动,stop,容器的停止,destroy,容器的销毁等阶段。源码如下:

public interface Lifecycle {


    /**
     * 初始化阶段
     */
    public void init() throws LifecycleException;

    /**
     * 启动阶段
     */
    public void start() throws LifecycleException;


    /**
     * 停止阶段
     */
    public void stop() throws LifecycleException;

    /**
     * 销毁阶段
     */
    public void destroy() throws LifecycleException;
}

LifecycleEvent定义各类事件,代表生命周期的各类阶段,事件的类型包括,before_init,after_init,start,before_start,等等。事件的源码如下:


/**
 * 生命周期事件
 **/
public final class LifecycleEvent extends EventObject {

    private static final long serialVersionUID = 1L;

    public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {

        super(lifecycle);
        this.type = type;
        this.data = data;
    }

    /**
     * The event data associated with this event.
     */
    private Object data = null;


    /**
     * The event type this instance represents.
     */
    private String type = null;

}

LifecycleListener定义事件监听器,监听LifecycleEvent事件,定义监听事件的具体操作。例如,容器关闭时,Session管理必须将Session对象保存到辅助存储器中。事件监听源码如下:


/**
 * 事件监听器
 *
 **/
public interface LifecycleListener {


    /**
     * Acknowledge the occurrence of the specified event.
     *
     * @param event LifecycleEvent that has occurred
     */
    public void lifecycleEvent(LifecycleEvent event);

}

LifecycleSupport事件广播接口,用于发布事件,在触发事件的地方调用发起对应事件的调用。事件发布的源码如下:

/**
 * 事件广播
 **/
public final class LifecycleSupport {

    ......

    /**
     * 生命周期监听器数组
     */
    private LifecycleListener listeners[] = new LifecycleListener[0];


    /**
     * 添加生命周期事件监听器
     */
    public void addLifecycleListener(LifecycleListener listener) {

    }

    /**
     * 发布事件
     */
    public void fireLifecycleEvent(String type, Object data) {

        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = listeners;
        for (int i = 0; i < interested.length; i++)
            interested[i].lifecycleEvent(event);

    }


    /**
     * 移除生命周期事件监听器
     */
    public void removeLifecycleListener(LifecycleListener listener) {

    }

}

zoomkeeper中watcher机制的实现

在zoomkeeper中使用watcher机制,实现zk客户端感知zk服务器对数据节点创建,修改,删除操作。该机制是基于事件驱动实现的。以zk服务器数据节点修改触发zk客户端操作的为例。zk客户端向zk服务器端注册watcher,在zk服务器修改该数据节点时,会基于TCP连接通知zk对应客户端,触发zk客户端注册的watcher,实现zk的watcher监听机制。流程如下:

事件驱动模式-Tomcat和zookeeper教你如何玩

WatchedEvent,定义了watcher事件。例如,None (-1),没有事件;NodeCreated (1),节点创建;NodeDeleted (2), 节点删除;NodeDataChanged (3), 节点数据修改;NodeChildrenChanged (4),节点子节点修改。源码如下:

public class WatchedEvent {
    /**
     * 通知状态
     */     
    final private KeeperState keeperState;
   /**
     * 事件类型
     */ 
    final private EventType eventType;
   /**
     * 事件触发的节点路径
     */
    private String path;
}
 

Watcher,事件监听的器,定义了监听各类事件的具体操作。例如,节点数据修改,zk客户端需要的具体操作。源码如下:

public interface Watcher {

   /**
     * 监听watcher事件,执行具体逻辑操作
     */
    abstract public void process(WatchedEvent event);
}

zk服务器定义WatchManager,实现事件的发布,大致流程是,定义封装可以序列化的WatchedEvent事件,通过与zk客户端建立的tcp连接发送请求。源码如下:

// zk服务器端的watcher事件发布器
public class WatchManager {
    
    /**
     *  向指定数据节点,发布指定类型的事件
     */
    public Set<Watcher> triggerWatch(String path, EventType type) {
        return triggerWatch(path, type, null);
    }

    public Set<Watcher> triggerWatch(String path, EventType type, Set<Watcher> supress) {
        WatchedEvent e = new WatchedEvent(type,
                KeeperState.SyncConnected, path);
        HashSet<Watcher> watchers;
        synchronized (this) {
            watchers = watchTable.remove(path);
            if (watchers == null || watchers.isEmpty()) {
                if (LOG.isTraceEnabled()) {
                    ZooTrace.logTraceMessage(LOG,
                            ZooTrace.EVENT_DELIVERY_TRACE_MASK,
                            "No watchers for " + path);
                }
                return null;
            }
            for (Watcher w : watchers) {
                HashSet<String> paths = watch2Paths.get(w);
                if (paths != null) {
                    paths.remove(path);
                }
            }
        }
        for (Watcher w : watchers) {
            if (supress != null && supress.contains(w)) {
                continue;
            }
            w.process(e);
        }
        return watchers;
    }
}

 

用户注册成功涉及业务的事件驱动设计

在用户注册成功后,通知会执行发送优惠券的操作,或者发送注册成功的短信,发送用户身份认证的通知等等操作。

ApplicationEvent应用事件。
ApplicationListener应用事件监听器。
ApplicationEventBroadcast事件广播。
GiftCouponListener发送优惠券事件监听,作为用户注册成功后,发送优惠券的逻辑。
UserRegistrationBroadcast定义了用户注册广播实现类,在用户注册成功的位置发布ApplicationEvent事件。

发送优惠券事件监听器GiftCouponListener的代码如下:


/**
 * 赠送优惠券的监听
 **/
public class GiftCouponListener implements ApplicationListener {

    @Override
    public void onEvent(ApplicationEvent applicationEvent) {

        Object param = applicationEvent.getParam();
        // TODO
        // 定义具体的实现逻辑
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

用户注册广播实现类UserRegistrationBroadcast代码如下:


/**
 * 用户注册广播
 **/
public class UserRegistrationBroadcast implements ApplicationEventBroadcast {

    private final List<ApplicationListener> listeners;

    public UserRegistrationBroadcast(List<ApplicationListener> listeners) {
        this.listeners = listeners;
        AnnotationAwareOrderComparator.sort(listeners);
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        listeners.forEach(applicationListener -> applicationListener.onEvent(event));
    }
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13648.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!