Spring源碼-監聽事件Applica**Listener和Applica**Event源碼分析

 Spring源碼-監聽事件ApplicationListener和ApplicationEvent源碼分析java

Spring中ApplicationListener和ApplicationEvent是典型的事件驅動模型,也就是咱們常說的發佈-訂閱模型 。其實咱們在開發中是常常用到這種發佈-訂閱模型模型的,發佈訂閱模型通常用在一對多的對象關係上,好比以下案例中,咱們就能用到這種發佈-訂閱模型。spring

案例:在用戶註冊成功後,每每還須要作其餘事。多線程

一、加積分併發

二、發確認郵件app

三、若是是遊戲賬戶,可能贈送遊戲大禮包ide

四、索引用戶數據源碼分析

在如上案例中,若是咱們業務量不大的時候,其實能夠直接用到Spring的發佈-訂閱模式就能解決,分別註冊四個監聽器,分別監聽四個步驟,每個監聽器去獨立的作一件事;使用這種模式還能將代碼解耦,還能結合多線程的優點來提供性能。post

1.  首先,咱們來初步使用如下Spring 的發佈-訂閱模式,以下是測試代碼。性能

先在配置文件中配置MyListen和MyListen2二個監聽器的Bean測試

<bean class="cn.edu.his.pay.listen.MyListen" />
<bean class="cn.edu.his.pay.listen.MyListen2" />

MyListen.java

package cn.edu.his.pay.listen;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class MyListen implements ApplicationListener {

	public void onApplicationEvent(ApplicationEvent arg0) {
		
		if(arg0 instanceof MyEvent) {
			MyEvent event = (MyEvent)arg0;
			
			System.out.println(this.getClass().getName() + event.getParam1());
			System.out.println(this.getClass().getName() + event.getParam2());
			System.out.println(this.getClass().getName() + event.getSource());
			
		}
	}
	
}

 MyListen2.java

package cn.edu.his.pay.listen;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class MyListen2 implements ApplicationListener {

	public void onApplicationEvent(ApplicationEvent arg0) {
		
		if(arg0 instanceof MyEvent) {
			MyEvent event = (MyEvent)arg0;
			
			System.out.println(this.getClass().getName() + event.getParam1());
			System.out.println(this.getClass().getName() + event.getParam2());
			System.out.println(this.getClass().getName() + event.getSource());
			
		}
	}
	
}

MyEvent.java

package cn.edu.his.pay.listen;

import org.springframework.context.ApplicationEvent;

public class MyEvent extends ApplicationEvent {
	
	public String param1;
	
	public String param2;
	
	public MyEvent(Object source,String param1,String param2) {
		super(source);
		this.param1 = param1;
		this.param2 = param2;
	}

	public Object getSource() {
		return super.getSource();
	}

	public String getParam1() {
		return param1;
	}

	public void setParam1(String param1) {
		this.param1 = param1;
	}

	public String getParam2() {
		return param2;
	}

	public void setParam2(String param2) {
		this.param2 = param2;
	}
	
}

Test.java

@Test
public void test() {
	// 往上下文context中發佈事件
	MyEvent event = new MyEvent("source","param1","param2");
	context.publishEvent(event);
}

輸出結果

cn.edu.his.pay.listen.MyListenparam1
cn.edu.his.pay.listen.MyListenparam2
cn.edu.his.pay.listen.MyListensource
cn.edu.his.pay.listen.MyListen2param1
cn.edu.his.pay.listen.MyListen2param2
cn.edu.his.pay.listen.MyListen2source

如上測試代碼結果能夠看出,經過自定義了一個MyEvent(主題)併發布到上下文中,這個時候只要有監聽器訂閱(觀察者)就能拿到主題信息去完成本身的業務。

2.  而後咱們就須要思考,Spring是怎麼作到的發佈訂閱了?如今咱們就結合Spring源碼來分析。

先看看Spring在初始化的時候都作了什麼? 入口:AbstractApplicationContext#registerListeners。

protected void registerListeners() {
	// Register statically specified listeners first.
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}
	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String lisName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(lisName);
	}
}

經過上面代碼能夠看出,在容器初始化的時候會將全部實現了ApplicationListener接口類beanName都先註冊applicationListenerBeans集合中,至關於註冊了全部的監聽器。

其次,咱們再看看發佈主題的時候context.publishEvent(event) 都作了什麼?入口:AbstractApplicationContext#publishEvent(ApplicationEvent event)。

@Override
public void publishEvent(ApplicationEvent event) {
	Assert.notNull(event, "Event must not be null");
	if (logger.isTraceEnabled()) {
		logger.trace("Publishing event in " + getDisplayName() + ": " + event);
	}
	getApplicationEventMulticaster().multicastEvent(event);
	if (this.parent != null) {
		this.parent.publishEvent(event);
	}
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void multicastEvent(final ApplicationEvent event) {
	for (final ApplicationListener listener : getApplicationListeners(event)) {
		Executor executor = getTaskExecutor();
		if (executor != null) {
			executor.execute(new Runnable() {
				@Override
				public void run() {
					listener.onApplicationEvent(event);
				}
			});
		}
		else {
			listener.onApplicationEvent(event);
		}
	}
}

經過如上代碼其實能夠看出,在發佈事件(主題)的時候,先經過getApplicationListeners(event)獲取了全部監聽器(觀察者),其實就是從以前Spring啓動時候註冊到applicationListenerBeans集合中取就行。取出全部的監聽器(觀察者),循環遍歷去調用監聽器(觀察者)onApplicationEvent方法。

相關文章
相關標籤/搜索