Java事件机制

Java的事件机制中有三种角色,分别是事件,事件监听器和事件发布者(事件源),事件机制并非一种技术,而是一种设计模式。

事件(Event)

事件用于封装源对象及其相关信息以便后续对事件进行处理,Java SE提供了自定义事件发布功能的基础类java.util.EventObject来实现事件类,自定义实现需要继承EventObject类,EventObject源码如下:

public class EventObject implements java.io.Serializable {

    private static final long serialVersionUID = 5516075349620653480L;

    /** 事件源对象 */
    protected transient Object  source;

    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");
        this.source = source;
    }

    public Object getSource() {
        return source;
    }

    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

事件监听器(EventLIstener)

Java SE提供了一个事件监听器接口,用于监听被发布的事件,针对不同的事件发布时机提供相应的处理方法定义。Java SE并未对监听器做具体实现要求,即提供的监听器接口是一个标记接口EventListener,自定义监听器的时候需要实现EventListener接口,表示该接口是一个监听器接口,具体方法自由定义

/**
 * A tagging interface that all event listener interfaces must extend.
 * @since JDK1.1
 */
public interface EventListener {
}

事件发布者(EventPublisher)

事件发布者作为事件源,应在合适的时间点,将相应的事件发布给对应的事件监听器,事件发布者完全由开发人员自己定义。

示例演示

(示例参考自《Spring揭秘》)
首先需要自定义一个事件类型,专门针对某具体场景,比方本文定义一个方法执行事件MethodExecutionEvent,该类继承EventObject。该类封装了事件发布者(事件源)source和方法名(相关信息)methodName,代码如下:

public class MethodExecutionEvent extends EventObject {

    /**方法名字段 */
    private String methodName;

    public MethodExecutionEvent(Object source) {
        super(source);
    }

    public MethodExecutionEvent(Object source, String methodName) {
        super(source);
        this.methodName = methodName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }
}

有了自定义的事件后,相应的需要一个监听器(接口),在合适的时机监听事件,以便后续对该事件进行处理,本文定义一个MethodExecutionEventListener接口,提供两个事件发布时机,代码如下:

public interface MethodExecutionEventListener extends EventListener {
    
    /** 处理方法开始执行时发布的MethodExecutionEvent时间 */
    void methodBegin(MethodExecutionEvent event);
    /** 处理方法执行完毕时发布的MethodExecutionEvent时间 */
    void methodEnd(MethodExecutionEvent event);

}

为了配合监听器接口定义的处理方法,额外定义一个枚举类,用于后续标记方法是开始执行还是实行完毕,定义如下:

public enum MethodExecutionStatus {
    METHOD_BEGIN(),
    METHOD_END();
}

接下来给出一个MethodExecutionEventListener的具体实现类SimpleMethodExecutionEventListener,具体代码如下:

public class SimpleMethodExecutionEventListener implements MethodExecutionEventListener{

    @Override
    public void methodBegin(MethodExecutionEvent event) {
        System.out.println(event.getMethodName() + "方法开始执行了!");
    }

    @Override
    public void methodEnd(MethodExecutionEvent event) {
        System.out.println(event.getMethodName() + "方法执行完毕了!");
    }

}

有了自定义的事件和自定义的事件监听器,剩下要做的就是正确的发布事件,然后交由相应的监听器监听并处理事件,为此需要一个事件发布者MethodExecutionEventPublisher,代码如下:

public class MethodExecutionEventPublisher {

    private List<MethodExecutionEventListener> listeners =
            new ArrayList<MethodExecutionEventListener>();


    //需要加以自定义事件处理的方法
    public void methodToMonitor(){
        MethodExecutionEvent event = new MethodExecutionEvent(this,"methodToMonitor");
        publishEvent(MethodExecutionStatus.METHOD_BEGIN,event);

        //methodToMonitor方法本身的实际逻辑
        System.out.println("methodToMonitor方法逻辑执行");

        publishEvent(MethodExecutionStatus.METHOD_END,event);
    }

    protected void publishEvent(MethodExecutionStatus status, MethodExecutionEvent methodExecutionEvent){
        List<MethodExecutionEventListener> copyOfListeners = new ArrayList<MethodExecutionEventListener>(listeners);
        for(MethodExecutionEventListener listener : copyOfListeners){
            if(status.equals(MethodExecutionStatus.METHOD_BEGIN)){
                listener.methodBegin(methodExecutionEvent);
            }else{
                listener.methodEnd(methodExecutionEvent);
            }
        }
    }

    public void addMethodExecutionEventListener(MethodExecutionEventListener listener){
        this.listeners.add(listener);
    }

    public void removeMethodExecutionEventListener(MethodExecutionEventListener listener){
        if(listeners.contains(listener))
            this.listeners.remove(listener);
    }

}

重点关注事件发布者的代码,类中的methodToMonitor是事件源,MethodExecutionEventPublisher需要在该方法本身的逻辑开始执行和执行结束时分别发布事件,后交由事件监听器处理。

其中发布者类中的成员变量并非是直接定义了监听器接口的实现类SimpleMethodExecutionEventListener,而是定义了一个MethodExecutionEventListener集合。这是因为,虽然本文示例之给出了这一个实现类,但在实际使用或其他场景中,可以有多个MethodExecutionEventListener的具体实现,比方其中一个实现类负责日志打印,另一个实现类负责其他功能,所以使用了集合。因此事件发布者除了在对的时间点发布事件这一职责外,还负责管理自定义事件监听器。

publishEvent方法中先对listeners进行克隆是为了防止在事件处理期间执行了添加或移除事件监听器操作,而影响事件处理。

最后进行测试,代码如下:

public class EventTest {

    public static void main(String[] args) {
        MethodExecutionEventPublisher publisher = new MethodExecutionEventPublisher();
        publisher.addMethodExecutionEventListener(new SimpleMethodExecutionEventListener());
        publisher.methodToMonitor();
    }

}

测试结果如下:

methodToMonitor方法开始执行了!
methodToMonitor方法逻辑执行
methodToMonitor方法执行完毕了!

Process finished with exit code 0

可见在methodToMonitor方法执行前后两个时间点,事件发布者正确的将事件发布,并由事件监听器监听到,最后加以处理。


以上便是本篇文章的全部内容
作者才疏学浅,如文中出现纰漏,还望指正