监听实现大致架构 1、根据监听的事件,嗅探出有哪些对该事件的监听器(类)。保存起来; 2、当事件发生事,通知该监听器,执行操作
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }Spring内部继承了ApplicationEvent的事件有很多,我在项目中用到的是: ContextRefreshedEvent ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用
实际项目使用
@Component public class OrderApplicationListener implements ApplicationListener<ContextRefreshedEvent> { /** 日志对象 */ private static Logger logger = LoggerFactory.getLogger(OrderApplicationListener.class); @Override public void onApplicationEvent(ContextRefreshedEvent event) { new Thread(() -> { while (true) { try { OrderInfo orderInfo = OrderDeferredResultSupporter.getCompleteOrderInfo(); logger.info("此时将对业务系统订单号的付费结果进行赋值:" + orderInfo.toString()); OrderDeferredResultSupporter.popDeferredResult(orderInfo.getOutTradeNo()).setResult(orderInfo); logger.info("业务订单号:" + orderInfo.getOutTradeNo() + "的付费结果为:" + orderInfo.toString()); } catch (Exception e) { logger.error("异步通知结果出现异常,异常为:", e); } } }).start(); }为什么要用@Component注解,才能使监听器生效 因为用@Component注解后,Spring才会管理该bean,将该bean注入到BeanFactory工厂后,注册监听器时,才能把该监听器注册进去。
该项目的具体调用堆栈分析,debug看什么时候进入该new Thread()处 1、最开始是Spring应用的main 2、调用refreshContext(context); 3、发布ContextRefreshedEvent事件; 4、广播事件ContextRefreshedEvent,找到相应的监听器,对该监听器进行触发。
关键步骤:getApplicationListeners–根据事件得到监听器
protected Collection<ApplicationListener<?>> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = (source != null ? source.getClass() : null); ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); // Quick check for existing entry on ConcurrentHashMap... ListenerRetriever retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { // Fully synchronized building and caching of a ListenerRetriever synchronized (this.retrievalMutex) { retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } retriever = new ListenerRetriever(true); Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { // No ListenerRetriever caching -> no synchronization necessary return retrieveApplicationListeners(eventType, sourceType, null); } }自定义的、用@Component进行注解的监听器何时被Spring探查到并存储 AbstractApplicationContext.refresh()方法中,会调用registerListeners();方法 该方法中,有根据是否继承ApplicationListener接口得到所有监听器Bean的方法。 会把所有监听器bean增加到ListenerRetriever.applicationListenerBeans集合中。
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); }备注: Spring中事件也可以自定义 然后监听自定义事件