导航

简单实现下监听

监听器提供了一种获取服务器运行状况、动态干预的方式,服务器在运行期间发生指定变化时及时介入干预。

 

首先我们定义一个监听事件的抽象类,所有事件都需要继承该类

 1 public abstract class AbstractEvent {
 2     //事件源
 3     protected Object source;
 4 
 5     public AbstractEvent(Object source) {
 6         this.source = source;
 7     }
 8 
 9     public Object getSource() {
10         return source;
11     }
12 
13     public void setSource(Object source) {
14         this.source = source;
15     }
16 
17 }

 

我们使用一个接口来表示事件监听器,是个泛型接口,后面的类型E表示当前监听器需要监听的事件类型,此接口中只有一个方法,用来实现处理事件的业务;其定义的监听器需要实现这个接口。

/**
 * 事件监听器
 *
 * @param <E> 当前监听器感兴趣的事件类型
 */
public interface  EventListener  <E extends AbstractEvent>{
    /**
     * 此方法负责处理事件
     *
     * @param event 要响应的事件对象
     */
    void onEvent(E event);

}

 

事件广播器

  • 讲白了就是在spring加载的时候去获取所有的EventListener 
/**
 * 事件广播器:
 * 1.负责事件监听器的管理(注册监听器&移除监听器,将事件和监听器关联起来)
 * 2.负责事件的广播(将事件广播给所有的监听器,对该事件感兴趣的监听器会处理该事件)
 */
public interface EventMulticaster {
    /**
     * 广播事件给所有的监听器,对该事件感兴趣的监听器会处理该事件
     *
     * @param event
     */
    void multicastEvent(AbstractEvent event);

    /**
     * 添加一个事件监听器(监听器中包含了监听器中能够处理的事件)
     *
     * @param listener 需要添加监听器
     */
    void addEventListener(EventListener<?> listener);


    /**
     * 将事件监听器移除
     *
     * @param listener 需要移除的监听器
     */
    void removeEventListener(EventListener<?> listener);
}

 

到这里为止,一个简单的监听器的框架已经大致搭建完成了,下面我们看下他的简单的实现

 

首先是对于AbstractEvent,我们需要定义一个具体的事件,基于这个是事件去完成我们的监听

public class UserRegisterSuccessEvent extends AbstractEvent {
    //用户名
    private String userName;

    /**
     * 创建用户注册成功事件对象
     *
     * @param source   事件源
     * @param userName 当前注册的用户名
     */
    public UserRegisterSuccessEvent(Object source, String userName) {
        super(source);
        this.userName = userName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;

    }
}

其次,对于监听器我们需要在事件触发的时候具体的去执行我们的实现,并且我们需要监听器在spring中被具体的感知,所以需要添加注解@Component

@Component
public class SendEmailOnUserRegisterSuccessListener implements EventListener<UserRegisterSuccessEvent>{
    @Override
    public void onEvent(UserRegisterSuccessEvent event) {
        System.out.println(
                String.format("给用户【%s】发送注册成功邮件!", event.getUserName()));
    }
}

 

然后,我们完成广播器的实现,把监听器放到容器中

/**
 * 事件广播器简单实现
 */
public class SimpleEventMulticaster implements EventMulticaster{
    private Map<Class<?>, List<EventListener>> eventObjectEventListenerMap = new ConcurrentHashMap<>();

    @Override
    public void multicastEvent(AbstractEvent event) {
        List<EventListener> eventListeners = this.eventObjectEventListenerMap.get(event.getClass());
        if (eventListeners != null) {
            for (EventListener eventListener : eventListeners) {
                eventListener.onEvent(event);
            }
        }
    }

    @Override
    public void addEventListener(EventListener<?> listener) {
        Class<?> eventType = this.getEventType(listener);
        List<EventListener> eventListeners = this.eventObjectEventListenerMap.get(eventType);
        if (eventListeners == null) {
            eventListeners = new ArrayList<>();
            this.eventObjectEventListenerMap.put(eventType, eventListeners);
        }
        eventListeners.add(listener);
    }

    @Override
    public void removeEventListener(EventListener<?> listener) {
        Class<?> eventType = this.getEventType(listener);
        List<EventListener> eventListeners = this.eventObjectEventListenerMap.get(eventType);
        if (eventListeners != null) {
            eventListeners.remove(listener);
        }

    }

    /**
     * 获取事件监听器需要监听的事件类型
     *
     * @param listener
     * @return
     */
    protected Class<?> getEventType(EventListener listener) {
        ParameterizedType parameterizedType = (ParameterizedType) listener.getClass().getGenericInterfaces()[0];
        Type eventType = parameterizedType.getActualTypeArguments()[0];
        return (Class<?>) eventType;
    }

}

接下来是最重要的,我们通过配置把获取监听器的List,把他放到容器里面,然后我们具体的服务可以去获取到这个容器从而进行广播,当事件发生的时候去触发具体的操作

public class ListenConfig {
    //这里是测试代码 这个bean会实列化两次,所以最好能在外面返回
    static EventMulticaster eventPublisher = new SimpleEventMulticaster();

    /**
     * 注册一个bean:事件发布者
     *
     * @param eventListeners
     * @return
     */
    @Bean
    public EventMulticaster eventMulticaster(List<EventListener> eventListeners) { //@1

        if (eventListeners != null) {
            eventListeners.forEach(eventPublisher::addEventListener);
        }
        return eventPublisher;
    }

    /**
     * 注册一个bean:用户注册服务
     *
     * @param eventMulticaster
     * @return
     */
    @Bean
    public UserRegisterService userRegisterService(EventMulticaster eventMulticaster) { //@2
        UserRegisterService userRegisterService = new UserRegisterService();
        userRegisterService.setEventMulticaster(eventMulticaster);
        return userRegisterService;
    }

}

业务代码

public class UserRegisterService {

    //事件发布者
    private EventMulticaster eventMulticaster; //@0

    /**
     * 注册用户
     *
     * @param userName 用户名
     */
    public void registerUser(String userName) { //@1
        //用户注册(将用户信息入库等操作)
        System.out.println(String.format("用户【%s】注册成功", userName)); //@2
        //广播事件
        UserRegisterSuccessEvent userRegisterSuccessEvent = new UserRegisterSuccessEvent(this, userName);
        this.eventMulticaster.multicastEvent(userRegisterSuccessEvent); //@3
    }

    public EventMulticaster getEventMulticaster() {
        return eventMulticaster;
    }

    public void setEventMulticaster(EventMulticaster eventMulticaster) {
        this.eventMulticaster = eventMulticaster;
    }
}

执行结果

2022-04-12 11:35:59.294  INFO 21068 --- [           main] c.example.listen.ListenApplicationTests  : Started ListenApplicationTests in 2.975 seconds (JVM running for 3.862)
用户【bosssoft小王】注册成功
给用户【bosssoft小王】发送注册成功邮件!
Disconnected from the target VM, address: '127.0.0.1:50071', transport: 'socket'

 

posted on 2022-04-12 14:13  dogDan  阅读(38)  评论(0编辑  收藏  举报