ApplicationListener与ApplicationEvent 使用及源码解析(上)

Spring提供ApplicationListener用来监听其他bean的事件,使用ApplicationContext容器对事件进行发布后,所有监听该事件的监听器,都将对该事件进行处理

类似于java的监听器模式,只是在实现上略有不同,基本的思想是一致的。

 

1.基于java.util.Observable实现的监听器

    * 被监听者Watched实现如下:

// 被监听对象
public class Watched extends Observable {
    private String data = "";
    
    public String getData() {
        return data;
    }

    public void setData(String data) {
        
        if(!this.data.equals(data)){
            this.data = data;
            // 修改状态
            setChanged();
        }
        // 通知所有观察者
        notifyObservers();
    }
}

    * 监听者实现如下:

// 监听器
public class Watcher implements Observer {

	public Watcher(Observable o) {
		o.addObserver(this);
	}

	@Override
	public void update(Observable o, Object arg) {
		System.out.println("statue changed:" + ((Watched) o).getData());
	}
}

    * 测试类

public class Test {
	public static void main(String[] args) {
		// create watcher
		Watched watched = new Watched();
		// create observer
		Observer watcher = new Watcher(watched);
		// set data
		watched.setData("now");
	}
}

    可以看到,当Watched发生变化时,监听器Watcher监听到事件变化,并执行update方法

 

2.基于Application的监听器

    * 创建被监听事件

@Data
// 监听器监听的对象
public class DemoEvent extends ApplicationEvent{

    private String msg;
    public DemoEvent(Object source,String msg) {
        super(source);
        this.setMsg(msg);
    }
}

    * 创建监听器,直接监听DemoEvent事件

@Component
public class DemoListener implements ApplicationListener<DemoEvent>{
    @Override
    public void onApplicationEvent(DemoEvent event) {
        String msg = event.getMsg();
        System.out.println("demoListener接受到了demoPublisher发布的消息:"+msg);
    }

}

    * 事件发布

@Component
public class DemoPublisher {

    @Autowired
    ApplicationContext context;

    public void published() {
        DemoEvent event = new DemoEvent(this, "发布成功!");
        System.out.println("发部event:"+event);
        context.publishEvent(event);
    }
}

    * 测试

@Configuration
@ComponentScan({"com.example.demo.eventListener"})
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EventConfig.class);
        DemoPublisher publisher = context.getBean(DemoPublisher.class);
        // 发布事件
        publisher.published();
        context.close();
    }
}

    注意,需要将以上的监听器及事件相关bean都注入到Spring中,否则不生效;

    可以看到,监听器监听到DemoEvent事件,并调用onApplicationEvent方法

 

3.ApplicationListener相关源码解析

    在Test类中,当发布事件后,调用ApplicationContext.publishEvent()方法,下面从该方法看起:

    1)由于当前的容器类为AnnotationConfigApplicationContext,故可知真正实现该方法的为AbstractApplicationContext类,代码如下:

protected void publishEvent(Object event, ResolvableType eventType) {
		...
		else {
            // 真正执行方法的语句
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}

    2)跟踪multicaseEvent方法,代码如下

	public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        // getApplicationListeners获取当前event所有的监听器
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(new Runnable() {
					@Override
					public void run() {
                        // 执行监听器的onApplicationEvent方法
						invokeListener(listener, event);
					}
				});
			}
			else {
                // 不存在executor的情况下,在这里执行监听器的onApplicationEvent方法
				invokeListener(listener, event);
			}
		}
	}

    由以上代码可知,在该方法中,获取event所有的监听事件,然后遍历执行监听器的onApplicationEvent方法,可知此方法是核心方法,是真正调用监听器的地方

 

    3)跟踪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);
        // 从map中获取,如果之前已经存在该key,则直接从map获取
		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);
                
                // map中没有该key,则先获取所有的监听器
				Collection<ApplicationListener<?>> listeners =
						retrieveApplicationListeners(eventType, sourceType, retriever);
                // 重新put到map中,下次可以直接从map中获取
				this.retrieverCache.put(cacheKey, retriever);
				return listeners;
			}
		}
		else {
			// No ListenerRetriever caching -> no synchronization necessary
			return retrieveApplicationListeners(eventType, sourceType, null);
		}
	}

   4)跟踪retrieveApplicationListeners方法,查看如何获取监听器列表

	private Collection<ApplicationListener<?>> retrieveApplicationListeners(
			ResolvableType eventType, Class<?> sourceType, ListenerRetriever retriever) {

		LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
		Set<ApplicationListener<?>> listeners;
		Set<String> listenerBeans;
		synchronized (this.retrievalMutex) {
            // 1.从defaultReviewer中获取监听器列表
			listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
			listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
		}
		for (ApplicationListener<?> listener : listeners) {
            // 2.针对于该Event事件的监听器,放入allListeners
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
					retriever.applicationListeners.add(listener);
				}
				allListeners.add(listener);
			}
		}
		if (!listenerBeans.isEmpty()) {
			BeanFactory beanFactory = getBeanFactory();
			for (String listenerBeanName : listenerBeans) {
				try {
					Class<?> listenerType = beanFactory.getType(listenerBeanName);
					if (listenerType == null || supportsEvent(listenerType, eventType)) {
						ApplicationListener<?> listener =
								beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        // 针对于该Event事件的监听器,并且不存在于allListeners中的,则放入allListeners
						if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
							if (retriever != null) {
								retriever.applicationListenerBeans.add(listenerBeanName);
							}
							allListeners.add(listener);
						}
					}
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Singleton listener instance (without backing bean definition) disappeared -
					// probably in the middle of the destruction phase
				}
			}
		}
		AnnotationAwareOrderComparator.sort(allListeners);
		return allListeners;
	}

    通过以上代码可确定,监听器列表是从defaultRetriever中获取的,那么defaultRetriever中的applicationListeners是如何被添加进来的呢?

    剩下的部分笔者写在另一篇文章ApplicationListener与ApplicationEvent 使用及源码解析(下)    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恐龙弟旺仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值