Spring中事件发布机制
当某件事件发生,为外部提供该事件的监听方法。
一、角色
事件类
- ApplicationEvent:定义事件类型
|------ApplicationContextEvent:ApplicationContext引发的事件的基类。
|------ContextClosedEvent:容器关闭事件
|------ContextRefreshedEvent:容器刷新事件
事件发布者
- ApplicationEventPublisher:将应用程序事件通知此应用程序注册的所有侦听器。
事件监听者
- ApplicationListener:由应用程序事件侦听器实现的接口。
事件广播器
- ApplicationEventMulticaster:
|------AbstractApplicationEventMulticaster:提供了基本的侦听器注册功能
|------SimpleApplicationEventMulticaster:实现事件通知具体方式
二、角色负责的功能
事件广播器
ApplicationEventMulticaster接口
定义规范:
- 把监听者加入集合
- 把监听者移出集合
- 事件通知
// 把事件事件监听者加入集合
void addApplicationListener(ApplicationListener<?> listener);
// 把事件事件监听者加入集合
void removeApplicationListener(ApplicationListener<?> listener);
/**
* 最终推送时间消息也会经过这个接口方法来处理谁该接收事件
*
* @param event
*/
void multicastEvent(ApplicationEvent event);
AbstractApplicationEventMulticaster抽象类
实现了:
- 创建集合用于存储
事件监听者(Listener)
- 实现将
事件监听者(Listener)
添加和移出集合的方法 - 实现将符合
事件
的监听者
添加入新建的集合并返回 - 拿出集合中所有的
监听者
,根据要发生的事件
判断,该监听者
是否感兴趣
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
// 存放所有ApplicationListener的集合
public final LinkedHashSet<ApplicationListener<ApplicationEvent>>
applicationListeners = new LinkedHashSet();
/**
* 方法主要是摘取符合广播事件中的监听处理器,具体过滤动作在 supportsEvent 方法中。
* @param event
* @return
*/
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event){
LinkedList<ApplicationListener> allListeners = new LinkedList<>();
for (ApplicationListener<ApplicationEvent> listener : applicationListeners){
if(supportsEvent(listener, event)) allListeners.add(listener);
}
return allListeners;
}
/**
* 监听器是否对该事件感兴趣
* 主要包括对 Cglib、Simple 不同实例化需要获取目标
* Class,Cglib 代理类需要获取父类的 Class,普通实例化的不需要。接下来就是通过
* 提取接口和对应的 ParameterizedType 和 eventClassName,方便最后确认是否为
* 子类和父类的关系,以此证明此事件归这个符合的类处理。
* @param applicationListener
* @param event
* @return
*/
private boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
// 按照 CglibSubclassingInstantiationStrategy、
// SimpleInstantiationStrategy 不同的实例化类型,需要判断后获取目标 class
Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ?
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 BeansException("wrong event class name: " + className);
}
// 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所
// 示的类或接口是否相同,或是否是其超类或超接口。
// isAssignableFrom 是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,
// 默认所有的类的终极父类都是 Object。如果 A.isAssignableFrom(B)结果是 true,证明 B 可以转换成
// 为 A,也就是 A 可以由 B 转换而来。
return eventClassName.isAssignableFrom(event.getClass());
}
......
}
SimpleApplicationEventMulticaster类
实现了:
- 实现了事件通知(具体细节由父类完成)
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(ApplicationEvent event) {
for(final ApplicationListener listener : getApplicationListeners(event)){
listener.onApplicationEvent(event);
}
}
.......
}
事件发布者
因为这边事件都是ApplicationContextEvent,Application是对Spring应用上下的管理。所以这边充当事件发布者
的是AbstractApplicationContext。
AbstractApplicationContext 间接实现ApplicationEventPublisher
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
private ApplicationEventMulticaster applicationEventMulticaster;
@Override
public void refresh() throws BeansException {
.....
// 一开始就创建了事件广播器
// 6. 初始化事件发布者
initApplicationEventMulticaster();
.......
// 9. 发布容器刷新完成事件(发布是容器刷新事件)
finishRefresh();
}
// 创建事件广播器
private void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
private void finishRefresh() {
publishEvent(new ContextRefreshedEvent(this));
}
@Override
public void publishEvent(ApplicationEvent event) {
applicationEventMulticaster.multicastEvent(event);
}
.......
}
事件监听者
当我们关心spring容器什么时候刷新,或者想在spring容器刷新的时候做一些事情。
监听关心的事件,主要就是在ApplicationListener中写对应的事件。
spring容器在刷新完容器,就会调用该方法。
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("刷新事件(容器刷新完成):" + this.getClass().getName());
}
}
三、使用spring中的事件机制
1.写一个事件类(暂定我们关心的是application上下文的事件)
public class CustomEvent extends ApplicationContextEvent {
private Long id;
private String message;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
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;
}
}
2.事件发布者
@Test
public void test_event(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.publishEvent(new CustomEvent(applicationContext, 101912455552221L, "事件发布成功!"));
//applicationContext.registerShutdownHook();
}
3.写对应的监听者实现就可以了
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("收到:" + event.getSource() + "消息;时间:" + new Date());
System.out.println("消息:" + event.getId() + ":" + event.getMessage());
}
}