事件监听属于观察者模式,可以降低系统的耦合
一、事件监听的几个要素
- 事件
- 监听器
- 发布器
- 广播器(串联其他三个组件)
二、事件
定义事件抽象类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