什么是事件
event即事件。每一个动作,每一步 *** 作,都可以称之为事件。
事件通知机制的作用
可以将相互耦合的代码解耦,保持功能的单一职责原则。
举个栗子:
注册用户时,需要给用户发送邮箱验证及短信通知。最粗暴的方法就是将邮箱逻辑和短信逻辑内嵌到注册方法中,进行方法调用,如果后续对邮箱和短信逻辑有另外的 *** 作,需要去对原有注册方法进行显示处理。
这样子实现功能和代码结构没什么太大的问题,也比较简单,但是不太利于扩展,对于某些需要扩展性和松耦合的场景不太友好。在这样的场景下,可以将邮箱和短信逻辑从显示调用切换为事件通知的隐式调用,将主要业务代码和扩展的额外代码进行解耦,如果扩展功能有变化,则不需要对原有主体业务进行改动。
2. Spring的Event使用示例为SpringBoot项目,版本为2.4.5。
-
定义一个事件
package cn.javayuli.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { private String msg; public MyEvent(Object source, String msg) { super(source); this.msg = msg; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
-
定义一个事件监听者
package cn.javayuli.config; import cn.javayuli.event.MyEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class MyEventListener implements ApplicationListener
{ @Override public void onApplicationEvent(MyEvent event) { System.out.println("自定义发布事件"); } } -
发布事件
package cn.javayuli.service; import cn.javayuli.event.MyEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @Service public class MyEventPublisher { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void publish(String msg) { MyEvent myEvent = new MyEvent(this, msg); applicationEventPublisher.publishEvent(myEvent); } }
-
junit测试
package cn.javayuli.test; import cn.javayuli.service.MyEventPublisher; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class AppTest { @Autowired private MyEventPublisher myEventPublisher; @Test public void testPublish() { myEventPublisher.publish("发布了一个自定义事件"); } }
从ApplicationEventPublisher类的publishEvent方法切入,ApplicationEventPublisher的实现类有AbstractApplicationContext。其中publishEvent方法的实现代码:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // 如有必要,将事件装饰为ApplicationEvent ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent>) applicationEvent).getResolvableType(); } } // 如果可能,立即传播-或者在传播主机初始化后延迟多播 if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { // 获取传播主机并传播事件 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // 也可以在父上下文中传播事件 if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
传播事件multicastEvent方法:
@Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); // 获取并发执行器 Executor executor = getTaskExecutor(); // 根据事件的类型获取到其所有的ApplicationListener监听类 for (ApplicationListener> listener : getApplicationListeners(event, type)) { if (executor != null) { // 异步执行listener类中的onApplicationEvent方法 executor.execute(() -> invokeListener(listener, event)); } else { // 同步执行listener类中的onApplicationEvent方法 invokeListener(listener, event); } } }
获取监听类getApplicationListeners方法:
protected Collection> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { // new MyEvent时传入的第一个参数,之前传的this,那就是MyEventPublisher类 Object source = event.getSource(); // cn.javayuli.service.MyEventPublisher Class> sourceType = (source != null ? source.getClass() : null); // 封装为ListenerCacheKey对象 ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); // Potential new retriever to populate CachedListenerRetriever newRetriever = null; // Quick check for existing entry on ConcurrentHashMap CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey); if (existingRetriever == null) { // Caching a new ListenerRetriever if possible if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { newRetriever = new CachedListenerRetriever(); // 如果cacheKey在retrieverCache中不存在则将键值对存入且返回newRetriever,否则返回retrieverCache中cacheKey对应的值 existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever); if (existingRetriever != null) { // 释放newRetriever对象 newRetriever = null; } } } if (existingRetriever != null) { // 获取existingRetriever中的ApplicationListener类与其beanName在beanFactory中对应的ApplicationListener bean Collection> result = existingRetriever.getApplicationListeners(); if (result != null) { return result; } // 如果结果为null,则现有检索器(existingRetriever)尚未完全由另一个线程填充。 // Proceed like caching wasn't possible for this current local attempt. } // 检索ApplicationListeners return retrieveApplicationListeners(eventType, sourceType, newRetriever); }
检索监听器retrieveApplicationListeners方法:
private Collection> retrieveApplicationListeners( ResolvableType eventType, @Nullable Class> sourceType, @Nullable CachedListenerRetriever retriever) { // 存放所有支持当前事件的监听器 List> allListeners = new ArrayList<>(); // 存放所有支持当前事件的的监听器实例 Set> filteredListeners = (retriever != null ? new linkedHashSet<>() : null); // 存放所有支持当前事件的bean名称 SetfilteredListenerBeans = (retriever != null ? new linkedHashSet<>() : null); Set> listeners; Set listenerBeans; synchronized (this.defaultRetriever) { listeners = new linkedHashSet<>(this.defaultRetriever.applicationListeners); listenerBeans = new linkedHashSet<>(this.defaultRetriever.applicationListenerBeans); } // Add programmatically registered listeners, including ones coming // from ApplicationListenerDetector (singleton beans and inner beans). for (ApplicationListener> listener : listeners) { if (supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { filteredListeners.add(listener); } allListeners.add(listener); } } // Add listeners by bean name, potentially overlapping with programmatically // registered listeners above - but here potentially with additional metadata. if (!listenerBeans.isEmpty()) { ConfigurableBeanFactory beanFactory = getBeanFactory(); for (String listenerBeanName : listenerBeans) { try { if (supportsEvent(beanFactory, listenerBeanName, eventType)) { ApplicationListener> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { if (beanFactory.isSingleton(listenerBeanName)) { filteredListeners.add(listener); } else { filteredListenerBeans.add(listenerBeanName); } } allListeners.add(listener); } } else { // Remove non-matching listeners that originally came from // ApplicationListenerDetector, possibly ruled out by additional // BeanDefinition metadata (e.g. factory method generics) above. Object listener = beanFactory.getSingleton(listenerBeanName); if (retriever != null) { filteredListeners.remove(listener); } allListeners.remove(listener); } } catch (NoSuchBeanDefinitionException ex) { // Singleton listener instance (without backing bean definition) disappeared - // probably in the middle of the destruction phase } } } AnnotationAwareOrderComparator.sort(allListeners); if (retriever != null) { if (filteredListenerBeans.isEmpty()) { retriever.applicationListeners = new linkedHashSet<>(allListeners); retriever.applicationListenerBeans = filteredListenerBeans; } else { retriever.applicationListeners = filteredListeners; retriever.applicationListenerBeans = filteredListenerBeans; } } return allListeners; }
这个方法总结起来就是,将所有可支持当前事件的监听器实例放入allListeners,将所有可支持当前事件的监听器实例和单例bean实例放入filteredListeners,将所有可支持当前事件的监听器的多例bean的名称放入filteredListenerBeans。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)