1.測(cè)試案例
定義一個(gè)事件
package com.example.demo.event;
import org.springframework.context.ApplicationEvent;
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
定義兩個(gè)listener
package com.example.demo.event;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class Listener1 implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
String source = (String) event.getSource();
System.out.println(this.getClass().getName() + ":" + source);
}
}
package com.example.demo.event;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class Listener2 implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
String source = (String) event.getSource();
System.out.println(this.getClass().getName() + ":" + source);
}
}
注入spring容器里的ApplicationEventPublisher對(duì)象,發(fā)布事件
package com.example.demo;
import com.example.demo.event.MyEvent;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@RunWith(SpringRunner.class)
@SpringBootTest
public class EventPublisherTest {
@Resource
private ApplicationEventPublisher eventPublisher;
@Test
public void test() {
eventPublisher.publishEvent(new MyEvent("xxx"));
}
}
2.DEBUG源碼分析
從eventPublisher.publishEvent(new MyEvent("xxx"));
進(jìn)去很容易就能找到,可以發(fā)現(xiàn)SimpleApplicationEventMulticaster這個(gè)事件發(fā)布對(duì)象持有所有l(wèi)istenter對(duì)象及MyEvent對(duì)象,
事件發(fā)布過(guò)程其實(shí)就是遍歷拿到每個(gè)listener對(duì)象并調(diào)用它自己的onApplicationEvent()
方法
SimpleApplicationEventMulticaster類的主要方法:
- addApplicationListener(ApplicationListener<?> listener) :
- addApplicationListenerBean(String listenerBeanName):
- removeApplicationListener(ApplicationListener<?> listener):
- removeApplicationListenerBean(String listenerBeanName):
- multicastEvent(ApplicationEvent event):廣播事件;
- multicastEvent(ApplicationEvent event, @Nullable
ResolvableType eventType):廣播事件,指定事件的source類型。
3. 異步監(jiān)聽(tīng)
從上圖斷點(diǎn)可以看到ApplicationEventMulticaster對(duì)象持有有taskExecutor字段為null,導(dǎo)致沒(méi)有異步執(zhí)行所有監(jiān)聽(tīng)器。這里需要想辦法這個(gè)字段設(shè)置線程池即可:
springboot默認(rèn)會(huì)配置一個(gè)ThreadPoolTaskExecutor對(duì)象在容器里,這里把它拿出來(lái)設(shè)置給ApplicationEventMulticaster對(duì)象即可
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @author Administrator
*/
@SpringBootApplication
public class DemoApplication {
@Resource
private SimpleApplicationEventMulticaster eventMulticaster;
@Resource
private ThreadPoolTaskExecutor executor;
@PostConstruct
public void setEventExecutor() {
eventMulticaster.setTaskExecutor(executor);
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
4.ApplicationListener子接口
還可以實(shí)現(xiàn)子類的getOrder方法可以實(shí)現(xiàn)多個(gè)監(jiān)聽(tīng)器排序;實(shí)現(xiàn)supportsEventType,supportsSourceType可以實(shí)現(xiàn)按過(guò)濾Class過(guò)來(lái)或按事件源Source的Class過(guò)濾
5. 注解支持
這里不通過(guò)實(shí)現(xiàn)接口來(lái)實(shí)現(xiàn)監(jiān)聽(tīng),順序排序,按事件類型過(guò)濾監(jiān)聽(tīng),采用更方便的注解實(shí)現(xiàn),且一個(gè)類中就可以實(shí)現(xiàn)多個(gè)監(jiān)聽(tīng)
package com.example.demo.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
public class Listener3 {
@Order(Integer.MIN_VALUE) // 優(yōu)先級(jí)最高
@EventListener(MyEvent.class) // 只監(jiān)聽(tīng)指定類型的事件
public void onApplicationEvent(ApplicationEvent event) {
MyEvent myEvent = (MyEvent) event;
System.out.println(this.getClass().getName() + ":" + myEvent.getSource());
}
}
6. 基于觀察者模式高仿spring事件監(jiān)聽(tīng)
6.1 先定義自定義一個(gè)事件
Java中已定義觀察者模式事件及監(jiān)聽(tīng)器頂級(jí)接口文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-655887.html
package com.example.demo.javanativeevent;
import java.util.EventObject;
public class MyJavaNativeEvent extends EventObject {
public MyJavaNativeEvent(Object source) {
super(source);
}
}
6.2 定義兩個(gè)監(jiān)聽(tīng)器
因?yàn)镴ava提供的EventListener無(wú)具體監(jiān)聽(tīng)方法,且無(wú)合適的子接口,故這里自定義一個(gè)類似spirng的子接口NativeEventListener
。這樣后續(xù)事件發(fā)布就是遍歷這種類型接口并調(diào)用onApplicationEvent()方法文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-655887.html
package com.example.demo.javanativeevent;
import java.util.EventListener;
import java.util.EventObject;
public interface NativeEventListener extends EventListener {
void onApplicationEvent(EventObject event);
}
package com.example.demo.javanativeevent;
import java.util.EventObject;
public class JavaNativeListener1 implements NativeEventListener {
@Override
public void onApplicationEvent(EventObject event){
String source = (String)event.getSource();
System.out.println(this.getClass().getName()+":"+source);
}
}
6.3 定義一個(gè)持有所有監(jiān)聽(tīng)器的對(duì)象,類似spring的SimpleApplicationEventMulticaster
package com.example.demo.javanativeevent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EventObject;
import java.util.List;
/**
* TODO
*
* @author majun
* @version 1.0
* @since 2023-08-13 18:50
*/
public class SimpleJavaNativeEventMulticaster {
public List<NativeEventListener> eventListeners= Collections.synchronizedList(new ArrayList<>(8));
public void addListener(NativeEventListener listener){
this.eventListeners.add(listener);
}
public void multicastEvent(EventObject eventObject){
eventListeners.stream().parallel().forEach(listener -> {
listener.onApplicationEvent(eventObject);
});
}
}
6.4 事件發(fā)布測(cè)試
package com.example.demo.javanativeevent;
/**
* TODO
*
* @author majun
* @version 1.0
* @since 2023-08-13 19:01
*/
public class EventPublishTest {
public static void main(String[] args) {
// 注冊(cè)兩個(gè)listener,這是spirng把這個(gè)過(guò)程隱藏在spring容器初始化過(guò)程中了
SimpleJavaNativeEventMulticaster eventMulticaster = new SimpleJavaNativeEventMulticaster();
eventMulticaster.addListener(new JavaNativeListener1());
eventMulticaster.addListener(new JavaNativeListener2());
// 發(fā)布事件
eventMulticaster.multicastEvent(new MyJavaNativeEvent("yyyy"));
}
}
到了這里,關(guān)于從源碼Debug深入spring事件機(jī)制,基于觀察者模式仿寫(xiě)spring事件監(jiān)聽(tīng)骨架的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!