其实在 JDK 提供相应的自定义事件发布功能的基本类别:
java.util.EventObject
类 :自定义事件类型java.util.EventListener
接口:事件监听器
首先,了解几个概念:
Spring 事件类结构1. 事件类事件类是定义发送的内容,例如可以继承ApplicationContextEvent
定义一个特定的事件类别。
ApplicationEvent
类首先是继承 EventObject
的ApplicationEvent
,事件源由source指定:
public abstract class ApplicationEvent extends EventObject { /** * Constructs a prototypical Event. * * @param source The object on which the Event initially occurred. * @throws IllegalArgumentException if source is null. */ public ApplicationEvent(Object source) { super(source); }}
1.2 ApplicationContextEvent
类它是容器启动、刷新、停止和关闭各种事件的主要子类。
public class ApplicationContextEvent extends ApplicationEvent { /** * Constructs a prototypical Event. * * @param source The object on which the Event initially occurred. * @throws IllegalArgumentException if source is null. */ public ApplicationContextEvent(Object source) { super(source); } /** * Get the <code>ApplicationContext</code> that the event was raised for. */ public final ApplicationContext getApplicationContext() { return (ApplicationContext) getSource(); }}public class ContextClosedEvent extends ApplicationContextEvent{ /** * Constructs a prototypical Event. * * @param source The object on which the Event initially occurred. * @throws IllegalArgumentException if source is null. */ public ContextClosedEvent(Object source) { super(source); }}public class ContextRefreshedEvent extends ApplicationContextEvent{ /** * Constructs a prototypical Event. * * @param source The object on which the Event initially occurred. * @throws IllegalArgumentException if source is null. */ public ContextRefreshedEvent(Object source) { super(source); }}
我们可以通过继承这一类来实现特定事件类型的需求,比如实现邮件发送事件。只需要继承ApplicationContextEvent
即可:
public class MailSendEvent extends ApplicationContextEvent { private String msg; public MailSendEvent(Object source, String msg) { super(source); this.msg = msg; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; }}
同时ApplicationContextEvent
还有几个特定的子类来表示容器启动、刷新、停止和关闭事件:
在事件监听器接口中,只定义了一种方法:onApplicationEvent(E event)
该方法接收ApplicationEvent
事件对象,在此方法中编写事件响应处理逻辑。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * 接收Applicationenentention 事件对象 * 在这种方法中编写事件响应处理的逻辑 * @param event */ void onApplicationEvent(E event);}
我们还可以实现接口,以实现特定的事件监听器功能,如邮件监听器:
public class MailSenderListener implements ApplicationListener<MailSendEvent> { @Override public void onApplicationEvent(MailSendEvent event) { System.out.println("邮件发送器 resource:" + event.getSource() + "邮件发送器 msg:" + event.getMsg()); }}
3.事件广播器事件广播器负责将事件通知监听器登记表中的事件监听器,然后由事件监听器分别响应事件。Spring定义了以下接口:
public interface ApplicationEventMulticaster { /** * 添加事件监听器 * @param listener */ void addApplicationListener(ApplicationListener<?> listener); /** * 移除事件监听器 * @param listener */ void removeApplicationListener(ApplicationListener<?> listener); /** * 广播事件 * @param event */ void multicastEvent(ApplicationEvent event);}
及其简单实现类SimpleApplicationEventMulticaster
:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster{ public SimpleApplicationEventMulticaster(BeanFactory beanFactory) { setBeanFactory(beanFactory); } /**unchecked 告诉编译器忽略指定的警告,无需编译后出现警告信息*/ @SuppressWarnings("unchecked") @Override public void multicastEvent(ApplicationEvent event) { for (ApplicationListener applicationListener : getApplicationListeners(event)) { applicationListener.onApplicationEvent(event); } }}
4.事件发布者作为事件源,它将在适当的时间向相应的事件监听器发布相应的事件:
public interface ApplicationEventPublisher { /** * 通知监听者并发布事件 * @param event */ void publishEvent(ApplicationEvent event);}
在Spring容器事件中,ApplicationContext
界面定义继承了ApplicationEventPublisher
接口,所以实际上AbstractApplicationContext
在事件中扮演事件发布者的角色。但事实上,在事件发布和事件监听器注册的具体实现中,将功能转移到ApplicationEventMulticaster
接口,最终具体实现放在那里AbstractApplicationEventMulticaster
实现类:
那么事件类在Spring中是如何工作的呢?首先,我们将在xml配置文件中配置相应的ApplicationListener
因此,在容器启动后,这些类型的bean将被使用ApplicationContext
对于容器识别,它们负责监控容器内相应的发布ApplicationEvent
类型事件。
<bean class="cn.ethan.springframework.test.event.ContextRefreshedEventListener"/><bean class="cn.ethan.springframework.test.event.MailSenderListener"/><bean class="cn.ethan.springframework.test.event.ContextClosedEventListener"/>
在AbstractApplicationContext
的refresh()
自动注册的内容可以在方法中看到:
public void refresh() throws BeansException { // 6. 初始化事件发布者 initApplicationEventMulticaster(); // 7. 注册事件监听器 registerListeners(); // 9. 发布容器刷新并完成事件 finishRefresh();}private void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);}private void registerListeners() { Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values(); for (ApplicationListener listener : applicationListeners) { applicationEventMulticaster.addApplicationListener(listener); }}private void finishRefresh() { publishEvent(new ContextRefreshedEvent(this));}public void publishEvent(ApplicationEvent event) { applicationEventMulticaster.multicastEvent(event);}
所以在ApplicationContext
当容器启动时,它将自动注册EventListener
类型的 Bean,一旦检测到ApplicationContextEvent
发布类型的事件将通知这些注册在容器中的事件EventListener
以下是发送邮件的Spring事件实例:
1. 邮件发送事件MailSendEvent
public class MailSendEvent extends ApplicationContextEvent { private String msg; public MailSendEvent(Object source, String msg) { super(source); this.msg = msg; } public String getMsg() { return msg; }}
2.邮件发送事件监听器MailSendListener
(邮件发送事件)、ContextRefreshedEventListener
(容器刷新事件) 和 ContextClosedEventListener
(容器关闭事件)public class MailSenderListener implements ApplicationListener<MailSendEvent> { @Override public void onApplicationEvent(MailSendEvent event) { System.out.println("邮件发送器 resource:" + event.getSource() + "邮件发送器 msg:" + event.getMsg()); }}
public class ContextClosedEventListener implements ApplicationListener<ContextClosedEvent> { @Override public void onApplicationEvent(ContextClosedEvent event) { System.out.println("关闭事件:" + this.getClass().getName()); }}
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.println("刷新/打开事件:" + this.getClass().getName()); }}
此时,将监听器注入xml文件:
<bean class="cn.ethan.springframework.test.event.ContextRefreshedEventListener"/><bean class="cn.ethan.springframework.test.event.MailSenderListener"/><bean class="cn.ethan.springframework.test.event.ContextClosedEventListener"/>
3.邮件发送事件发布者事件发布者ApplicationEventPublisher
,因为前面提到的,applicationContext
继承了ApplicationEventPublisher
,而applicationContext
委托事件发布功能。ApplicationEventMulticaster
,启动容器时,检查是否有名称applicationEventMulticaster
的 ApplicationEventMulticaster
对象实例,如果有实现提供的实现,如果没有,默认初始化SimpleApplicationEventMulticaster
作为将要使用的东西ApplicationEventMulticaster
/** * @description: 事件监听器管理功能的实现 * @author: wjw * @date: 2022/7/9 */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 void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } /** * 获得监听器 * @param event * @return */ protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) { LinkedList<ApplicationListener> allListeners = new LinkedList<>(); for (ApplicationListener<ApplicationEvent> listener : allListeners) { if (supportsEvent(listener, event)) { allListeners.add(listener); } } return allListeners; } protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) { Class<? extends ApplicationListener> listenerClass = applicationListener.getClass(); /**根据不同的实例类型,判断后获得相应的目标 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); } return eventClassName.isAssignableFrom(event.getClass()); }}
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster{ public SimpleApplicationEventMulticaster(BeanFactory beanFactory) { setBeanFactory(beanFactory); } /**unchecked 告诉编译器忽略指定的警告,无需编译后出现警告信息*/ @SuppressWarnings("unchecked") @Override public void multicastEvent(ApplicationEvent event) { for (ApplicationListener applicationListener : getApplicationListeners(event)) { applicationListener.onApplicationEvent(event); } }}
4.测试验证public void test_event() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml"); applicationContext.publishEvent(new CustomEvent(applicationContext, 110L, "test!")); System.out.println("-----------------------------------------------------------------"); applicationContext.publishEvent(new MailSendEvent(applicationContext, "邮件发送测试")); applicationContext.registerShutdownHook();}
刷新/打开事件:cn.ethan.springframework.test.event.ContextRefreshedEventListener$$EnhancerByCGLIB$$邮件发送器2e5c458- resource:cn.ethan.springframework.context.support.ClassPathXmlApplicationContext@5f2050f6邮件发送器 msg:邮件发送测试关闭事件:cn.ethan.springframework.test.event.ContextClosedEventListener$$EnhancerByCGLIB$$fbc2c978