基于Spring 写监听者模式 Listener

本文介绍了如何使用Spring实现监听者模式,通过创建EventBroadcaster事件发布器、ModelEvent事件类和EventListener监听器接口,实现了代码解耦。通过@Order或@Priority注解控制监听器执行顺序,并提供测试类展示事件发布和消费过程,适用于扩展新的事件和监听器。
摘要由CSDN通过智能技术生成

背景

为了代码解耦,一些与主业务无关的内容最好和主业务分开,我这里写了一个基于事件监听的模型,记录一下。

代码结构

在这里插入图片描述
EventBroadcaster 是事件发布器,
ModelEvent继承自java.util.EventObject代表一个具体的事件
EventListener是监听器的接口
ModelEventListenerModelEventListener2为监听ModelEvent的2个监听器,监听器之间的顺序可以使用spring的@Order注解或者java的@javax.annotation.Priority来控制

具体代码

package com.siiirius.event;

import java.util.EventObject;

/**
* 顶层监听器接口
 * Created by siiiriu on 2020/7/6.
 */
public interface EventListener<E extends EventObject> extends java.util.EventListener {
    /**
     * process method
     *
     * @param event
     */
    void process(E event);
}
package com.siiirius.model;

import java.io.Serializable;

/**
* 一个具体数据模型
 * Created by siiiriu on 2020/7/6.
 */
public class Model implements Serializable{
    private static final long serialVersionUID = 42L;

    private Long id;

    private String name;


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Model{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
package com.siiirius.event;

import com.siiirius.model.Model;

import java.util.EventObject;

/**
*  Model模型产生的事件
 * Created by siiiriu on 2020/7/6.
 */
public class ModelEvent extends EventObject {
    private static final long serialVersionUID = 42L;

    public ModelEvent(Model model) {
        super(model);
    }


    @Override
    public Model getSource() {
        return (Model)super.getSource();
    }
}
package com.siiirius.event;


import org.springframework.stereotype.Component;

/**
* 一个model事件的监听器
 * Created by siiiriu on 2020/7/6.
 */
@Component
public class ModelEventListener implements EventListener<ModelEvent> {
    @Override
    public void process(ModelEvent event) {
        System.out.println("process 1." + event.getSource());
    }
}
package com.siiirius.event;


import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
* 另外一个Model事件的监听器,希望比ModelEventListener要早执行
 * Created by siiiriu on 2020/7/6.
 */
@Component
@Order(0)
public class ModelEventListener2 implements EventListener<ModelEvent> {
    @Override
    public void process(ModelEvent event) {
        System.out.println("process 2." + event.getSource());
    }
}
package com.siiirius.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
* 事件发布器,使用静态方法EventBroadcaster.broadcastEvent(..)发布一个事件
 * Created by siiiriu on 2020/7/6.
 */
@Component
public class EventBroadcaster {

    private static EventBroadcaster instance;

    Map<Class<? extends EventObject>, List<EventListener<? extends EventObject>>> map = new HashMap<>();


    @Autowired
    private List<EventListener<? extends EventObject>> listeners;


    @PostConstruct
    public void init() {
        instance = this;

        if (CollectionUtils.isEmpty(listeners)) {
            return;
        }


        for (EventListener<? extends EventObject> listener : listeners) {
            Class<? extends EventObject> c = getListenEventClass(listener);
            map.computeIfAbsent(c, key -> new ArrayList<>()).add(listener);
        }

		// 排序,使用Spring的排序
        for (List<EventListener<? extends EventObject>> eventListeners : map.values()) {
            eventListeners.sort(AnnotationAwareOrderComparator.INSTANCE);
        }

    }
	// 获取泛型
    private Class<? extends EventObject> getListenEventClass(EventListener<? extends EventObject> listener) {
        ParameterizedType  type = (ParameterizedType)listener.getClass().getGenericInterfaces()[0];
        return (Class<? extends EventObject>) type.getActualTypeArguments()[0];
    }


    /**
     * 发布事件
     *
     * @param event
     */
    public static void broadcastEvent(EventObject event) {
        instance.broadcast(event);
    }


    private void broadcast(EventObject eventObject) {
        List<EventListener<? extends EventObject>> eventListeners = map.get(eventObject.getClass());
        if (eventListeners == null) {
            //log
            return;
        }

        for (EventListener<? extends EventObject> eventListener : eventListeners) {
            EventListener<EventObject> listener = (EventListener<EventObject>) eventListener;
            listener.process(eventObject);
        }
    }

}

然后我们来一个测试类

import com.siiirius.event.EventBroadcaster;
import com.siiirius.event.ModelEvent;
import com.siiirius.event.ModelEventListener;
import com.siiirius.event.ModelEventListener2;
import com.siiirius.model.Model;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * Created by siiiriu on 2020/7/6.
 */
@ContextConfiguration(
        classes = {
                EventBroadcaster.class,
                ModelEventListener.class,
                ModelEventListener2.class
        }
)
@RunWith(SpringRunner.class)
public class EventBroadcasterTest {


    @Test
    public void test() {
        Model model = new Model();
        model.setId(1L);
        model.setName("name");

        EventBroadcaster.broadcastEvent(new ModelEvent(model));
    }


}

执行结果

process 2.Model{id=1, name='name'}
process 1.Model{id=1, name='name'}

框架已经搭好了,后面只需要增加Event以及对应的Listener,然后在需要发布事件的位置使用EventBroadcaster.broadcastEvent(…)就可以发布并且消费事件了。

后续,可以考虑增加线程池异步执行任务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值