chapter10_事件监听

事件监听属于观察者模式,可以降低系统的耦合

一、事件监听的几个要素

  • 事件
  • 监听器
  • 发布器
  • 广播器(串联其他三个组件)

二、事件

定义事件抽象类ApplicationEvent,继承自java.util.EventObject,定义出具备事件功能的抽象类 ,后续所有事件的类都需要继承这个类。source表示触发事件的对象

public abstract class ApplicationEvent extends EventObject {
    public ApplicationEvent(Object source) {
        super(source);
    }
}

定义ApplicationContextEvent基础类,继承上面创建的ApplicationEvent,表示spring应用上下文触发的事件

public class ApplicationContextEvent extends ApplicationEvent {
    public ApplicationContextEvent(Object source) {
        super(source);
    }

    public final ApplicationContext getApplicationContext() {
        return (ApplicationContext) getSource();
    }
}

新建三个事件实现类

  • 上下文刷新事件ContextRefreshedEvent,继承ApplicationContextEvent
public class ContextRefreshedEvent extends ApplicationContextEvent{
    public ContextRefreshedEvent(Object source) {
        super(source);
    }
}
  • 上下文关闭事件ContextClosedEvent,继承ApplicationContextEvent
public class ContextClosedEvent extends ApplicationContextEvent{
    public ContextClosedEvent(Object source) {
        super(source);
    }
}
  • 自定义事件CustomEvent,继承ApplicationContextEvent,提供两个属性,供测试使用
public class CustomEvent extends ApplicationContextEvent {
    private Long id;
    private String message;
    
    
    public CustomEvent(Object source, Long id, String message) {
        super(source);
        this.id = id;
        this.message = message;
    }

    public Long getId() {
        return id;
    }

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

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

三、监听器

负责监听特定的事件,并处理业务逻辑

定义一个监听器接口,继承自java.util.EventListener

  • 监听的特定事件event使用泛型E表示,继承自事件抽象类ApplicationEvent
  • 接收到事件的时候,会自动调用onApplicationEvent
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E event);
}

自定义实现类一

@Slf4j
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        log.info("收到:" + event.getSource() + "消息;时间:" + new Date());
        log.info("消息:" + event.getId() + ":" + event.getMessage());
    }
}

自定义实现类二

@Slf4j
public class ContextClosedEventListener implements ApplicationListener<ContextClosedEvent> {
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        log.info("监听到了容器关闭事件");
    }
}

自定义实现类三

@Slf4j
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        log.info("监听到了容器刷新事件");
    }
}

三、发布器

定义事件发布者接口,所有的事件都需要从这个接口发布出去

public interface ApplicationEventPublisher {
    /**
     * Notify all listeners registered with this application of an application
     * event. Events may be framework events (such as RequestHandledEvent)
     * or application-specific events.
     * @param event the event to publish
     */
    void publishEvent(ApplicationEvent event);
}

ApplicationContext接口继承了ApplicationEventPublisher,并由AbstractApplicationContext实现,最终通过事件广播器,发布事件

四、事件广播器

事件广播器接口,负责事件的广播发布,此接口定义了三个方法

  • 新增一个监听器
  • 移除一个监听器
  • 广播事件
public interface ApplicationEventMulticaster {

    /**
     * Add a listener to be notified of all events.
     * @param listener the listener to add
     */
    void addApplicationListener(ApplicationListener<?> listener);

    /**
     * Remove a listener from the notification list.
     * @param listener the listener to remove
     */
    void removeApplicationListener(ApplicationListener<?> listener);

    /**
     * Multicast the given application event to appropriate listeners.
     * @param event the event to multicast
     */
    void multicastEvent(ApplicationEvent event);

}

提供一个抽象类,实现事件广播器的基础功能

  • 实现addApplicationListener与removeApplicationListener方法
  • 实现BeanFactoryAware接口,这里特殊处理了,手动传递BeanFactory,没有让Spring自动传递
  • 关键方法supportsEvent,判断事件监听器是否监听了特定的事件
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    @Override
    public final void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
        LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
            if (supportsEvent(listener, event)) allListeners.add(listener);
        }
        return allListeners;
    }

    /**
     * 监听器是否对该事件感兴趣
     */
    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();

        // 按照 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 不同的实例化类型,需要判断后获取目标 class
        Class<?> targetClass = listenerClass.getName().contains("$$") ? listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("wrong event class name: " + className);
        }
        // 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同,或是否是其超类或超接口。
        // isAssignableFrom是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true,证明B可以转换成为A,也就是A可以由B转换而来。
        return eventClassName.isAssignableFrom(event.getClass());
    }

}

提供事件广播器实现类SimpleApplicationEventMulticaster ,并作为属性由AbstractApplicationContext持有

  • 事件广播器每一次广播事件,都会遍历所有的监听器,看看监听器是否响应事件,如果是则调用对应的onApplicationEvent
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
        setBeanFactory(beanFactory);
    }

    @Override
    public void multicastEvent(ApplicationEvent event) {
        for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
            if (supportsEvent(applicationListener, event)) {
                applicationListener.onApplicationEvent(event);
            }
        }
    }
}

五、重写生命周期

@Override
public void refresh() {

		......

    // 6.初始化事件广播器
    initApplicationEventMulticaster();

    // 7. 注册事件监听器
    registerListeners();

    ......

    // 9. 发布容器刷新完成事件
    finishRefresh();
}

初始化事件广播器

private void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //直接加入了单例池,并没有BeanDefinition,不会触发Bean后置处理器,也就是不会自动调用setBeanFactory
    //所以需要传入beanFacroty
    applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
}

注册事件监听器

protected void registerListeners() {
    Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
    for (ApplicationListener applicationListener : applicationListeners) {
        applicationEventMulticaster.addApplicationListener(applicationListener);
    }
}

发布容器刷新完成事件

/**
 * 发布容器刷新完成事件
 */
protected void finishRefresh() {
    publishEvent(new ContextRefreshedEvent(this));
}

@Override
public void publishEvent(ApplicationEvent event) {
    applicationEventMulticaster.multicastEvent(event);
}

发布容器关闭事件

@Override
public void close() {

    // 发布容器关闭事件
    publishEvent(new ContextClosedEvent(this));

    // 执行销毁单例bean的销毁方法
    getBeanFactory().destroySingletons();
}

Spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean class="cn.shopifymall.springframework.test.event.ContextRefreshedEventListener"/>

    <bean class="cn.shopifymall.springframework.test.event.CustomEventListener"/>

    <bean class="cn.shopifymall.springframework.test.event.ContextClosedEventListener"/>

</beans>

测试类

@Test
public void test_event() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    applicationContext.publishEvent(new CustomEvent(applicationContext, 1019129009086763L, "成功了!"));

    applicationContext.registerShutdownHook();
}

控制台效果

Connected to the target VM, address: '127.0.0.1:7011', transport: 'socket'
02:56:23.425 [main] INFO cn.shopifymall.springframework.test.event.ContextRefreshedEventListener - 监听到了容器刷新事件
02:56:23.430 [main] INFO cn.shopifymall.springframework.test.event.CustomEventListener - 收到:cn.shopifymall.springframework.context.support.ClassPathXmlApplicationContext@23529fee消息;时间:Fri Feb 14 02:56:23 CST 2025
02:56:23.430 [main] INFO cn.shopifymall.springframework.test.event.CustomEventListener - 消息:1019129009086763:成功了!
02:56:23.433 [Thread-0] INFO cn.shopifymall.springframework.test.event.ContextClosedEventListener - 监听到了容器关闭事件
Disconnected from the target VM, address: '127.0.0.1:7011', transport: 'socket'

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值