Spring之事件監聽(觀察者模型)


  本文介紹下Spring中的事件監聽,其本質也就是觀察者模型(發布/訂閱模式),具體的觀察者模式參考下文


Java觀察者模式(Observer)


@

Spring事件監聽

一、事件監聽案例

1.事件類

/**
 * 事件類
 * @author 波波烤鴨
 * @email dengpbs@163.com
 *
 */
public class MyEvent extends ApplicationContextEvent {

	private static final long serialVersionUID = 1L;
	
	public MyEvent(ApplicationContext source) {
		super(source);
		System.out.println("myEvent 構造方法被執行了...");
	}
	
	public void out(String name){
		System.out.println("myEvent .... out方法執行了"+name);
	}
}

2.事件監聽類

  事件監聽器也就是我們的觀察者。我們可以創建多個來觀察。

/**
 * 監聽器
 *    觀察者
 * @author 波波烤鴨
 * @email dengpbs@163.com
 *
 */
public class MyListenerA implements ApplicationListener<MyEvent>{

	@Override
	public void onApplicationEvent(MyEvent event) {
		System.out.println("MyListenerA 監聽器觸發了...");
		// 執行事件中的特定方法
		event.out("AAAAA");
	}
}
/**
 * 監聽器
 *    觀察者
 * @author 波波烤鴨
 * @email dengpbs@163.com
 *
 */
public class MyListenerB implements ApplicationListener<MyEvent>{

	@Override
	public void onApplicationEvent(MyEvent event) {
		System.out.println("MyListenerB 監聽器觸發了...");
		// 執行事件中的特定方法
		event.out("BBBBB");
	}
}

3.事件發布者

/**
 * 事件發布類
 *   實現ApplicationContextAware接口用來感知ApplicationContext對象
 * @author 波波烤鴨
 * @email dengpbs@163.com
 *
 */
public class MyPublisher implements ApplicationContextAware{
	
	public ApplicationContext ac;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// TODO Auto-generated method stub
		this.ac = applicationContext;
	}
	/**
	 * 發布事件
	 *    監聽該事件的監聽者都可以獲取消息
	 * @param event
	 */
	public void publisherEvent(ApplicationEvent event){
		System.out.println("---發布事件---"+event);
		ac.publishEvent(event);
	}
}

4.配置文件中注冊

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	
	<context:annotation-config/>

	<bean class="com.dpb.pojo.User" id="user"  >
		<property name="name" value="波波烤鴨"></property>
	</bean>
	
	<!-- 注冊事件類 -->
	<bean class="com.dpb.event.MyEvent"></bean>
	
	<!-- 注冊監聽器 -->
	<bean class="com.dpb.listener.MyListenerA"></bean>
	<bean class="com.dpb.listener.MyListenerB"></bean>
	
	<!-- 注冊發布者類 -->
	<bean class="com.dpb.publisher.MyPublisher"></bean>
</beans>

5.測試

@Test
public void test1() {
	ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
	// 從Spring容器中獲取發布者
	MyPublisher bean = ac.getBean(MyPublisher.class);
	// 從Spring容器中獲取事件對象
	MyEvent event = ac.getBean(MyEvent.class);
	// 發布者發布事件
	bean.publisherEvent(event);
}

輸出結果

myEvent 構造方法被執行了...
---發布事件---com.dpb.event.MyEvent[source=org.springframework.context.support.ClassPathXmlApplicationContext@311d617d: startup date [Wed Mar 06 13:04:57 CST 2019]; root of context hierarchy]
MyListenerA 監聽器觸發了...
myEvent .... out方法執行了AAAAA
MyListenerB 監聽器觸發了...
myEvent .... out方法執行了BBBBB

小結:通過案例我們實現了事件發生后注冊的有此事件的監聽者(觀察者)監聽到了此事件,並做出了響應的處理。

二、Spring中事件監聽分析

1. Spring中事件監聽的結構

在這里插入圖片描述

2. 核心角色介紹

2.1 ApplicationEvent

  ApplicationEvent是所有事件對象的父類。ApplicationEvent繼承自jdk的EventObject,所有的事件都需要繼承ApplicationEvent,並且通過source得到事件源。

public abstract class ApplicationEvent extends EventObject {

	/** use serialVersionUID from Spring 1.2 for interoperability */
	private static final long serialVersionUID = 7099057708183571937L;

	/** System time when the event happened */
	private final long timestamp;


	/**
	 * Create a new ApplicationEvent.
	 * @param source the object on which the event initially occurred (never {@code null})
	 */
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}
	/**
	 * Return the system time in milliseconds when the event happened.
	 */
	public final long getTimestamp() {
		return this.timestamp;
	}
}

實現類:
在這里插入圖片描述

2.2 ApplicationListener

  ApplicationListener事件監聽器,也就是觀察者。繼承自jdk的EventListener,該類中只有一個方法onApplicationEvent。當監聽的事件發生后該方法會被執行。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);
}

實現類
在這里插入圖片描述

2.3 ApplicationContext

  ApplicationContext是Spring中的核心容器,在事件監聽中ApplicationContext可以作為事件的發布者,也就是事件源。因為ApplicationContext繼承自ApplicationEventPublisher。在ApplicationEventPublisher中定義了事件發布的方法

public interface ApplicationEventPublisher {

	/**
	 * Notify all <strong>matching</strong> listeners registered with this
	 * application of an application event. Events may be framework events
	 * (such as RequestHandledEvent) or application-specific events.
	 * @param event the event to publish
	 * @see org.springframework.web.context.support.RequestHandledEvent
	 */
	void publishEvent(ApplicationEvent event);

	/**
	 * Notify all <strong>matching</strong> listeners registered with this
	 * application of an event.
	 * <p>If the specified {@code event} is not an {@link ApplicationEvent},
	 * it is wrapped in a {@link PayloadApplicationEvent}.
	 * @param event the event to publish
	 * @since 4.2
	 * @see PayloadApplicationEvent
	 */
	void publishEvent(Object event);

}

在這里插入圖片描述
具體發布消息的方法實現:AbstractApplicationContext中

protected void publishEvent(Object event, ResolvableType eventType) {
	Assert.notNull(event, "Event must not be null");
	if (logger.isTraceEnabled()) {
		logger.trace("Publishing event in " + getDisplayName() + ": " + event);
	}

	// Decorate event as an ApplicationEvent if necessary
	ApplicationEvent applicationEvent;
	if (event instanceof ApplicationEvent) {
		applicationEvent = (ApplicationEvent) event;
	}
	else {
		applicationEvent = new PayloadApplicationEvent<Object>(this, event);
		if (eventType == null) {
			eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
		}
	}

	// Multicast right now if possible - or lazily once the multicaster is initialized
	if (this.earlyApplicationEvents != null) {
		this.earlyApplicationEvents.add(applicationEvent);
	}
	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);
		}
	}
}

getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);這行代碼的作用是獲取ApplicationEventMulticaster來廣播事件給所有的監聽器。

2.4 ApplicationEventMulticaster

  事件廣播器,它的作用是把Applicationcontext發布的Event廣播給所有的監聽器.

在這里插入圖片描述
具體的注冊監聽是在AbstractApplicationContext中實現的。

@Override
public void addApplicationListener(ApplicationListener<?> listener) {
	Assert.notNull(listener, "ApplicationListener must not be null");
	if (this.applicationEventMulticaster != null) {
		this.applicationEventMulticaster.addApplicationListener(listener);
	}
	else {
		this.applicationListeners.add(listener);
	}
}

三、總結

  1. Spring中的事件監聽使用的是觀察者模式
  2. 所有事件需要繼承ApplicationEvent父類
  3. 所有的監聽器需要實現ApplicationListener接口
  4. 事件發布需要通過ApplicationContext中的publisherEvent方法實現
  5. 監聽器的注冊是ApplicationEventMulticaster提供的,但我們並不需要實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM