【spring原始碼】十二、監聽器
spring監聽器
一、ApplicationListener介面
作用:監聽容器中釋出的事件,完成事件驅動開發
實現ApplicationListener介面
//如果要寫實現類就得實現這個介面
public interface ApplicationListener<E extends ApplicationEvent> //泛型是要監聽的事件,監聽ApplicationEvent及其下面的子事件。即我們要釋出事件,這個事件應該是ApplicationEvent的子類
extends EventListener {//處理一個事件
//事件到達以後,出觸發該方法
void onApplicationEvent(E event);
}
1 自定義實現
@Component //把監聽器加入到容器中
public class MyApplicationListener //寫一個監聽器來監聽某個事件(ApplicationEvent及其子類)
implements ApplicationListener<ApplicationEvent> {
//當容器中釋出此事件以後,方法觸發//預設的話我們會收到ContextRefreshedEvent和ContextClosedEvent兩個事件,即容器重新整理完和關閉的事件。而還有兩個事件是cotextStartedEvent和ContextStopedEvent事件沒有使用
@Override
public void onApplicationEvent(ApplicationEvent event) {
// TODO Auto-generated method stub
System.out.println("收到事件:"+event);//分為開啟、關閉
}
}
// 也可以@EventListener
@Service
public class UserService {
@EventListener(classes={ApplicationEvent.class})//原理:使用EventListenerMethodProcessor處理器解析方法上的@EventListener // 可以看EventListenerMethodProcessor
public void listen(ApplicationEvent event){
System.out.println("UserService。。監聽到的事件:"+event);
}
}
2 自己釋出事件
applicationContext.publishEvent(new ApplicationEvent(new String("我釋出的事件"))
public class IOCTest_Ext {
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
//自己釋出事件;//這裡我們釋出了一個容器時間
applicationContext.publishEvent(new ApplicationEvent(new String("我釋出的事件")) {
});
applicationContext.close();
}
}
//我們這裡釋出publish了事件,在MyApplicationListener就會監聽到,並傳入到event引數,此時就列印出了2+1=3個事件
二、事件監聽器流程
原理:
* ContextRefreshedEvent、IOCTest_Ext$1[source=我釋出的時間]、ContextClosedEvent;
* 1)、ContextRefreshedEvent事件:
* 1)、容器建立物件:refresh();
* 2)、⑫finishRefresh();容器重新整理完成會發布ContextRefreshedEvent事件
* 2)、自己釋出事件;
* 3)、容器關閉會發布ContextClosedEvent;
*
* 【事件釋出流程】:
* 3)、publishEvent(new ContextRefreshedEvent(this));
* 1)、獲取事件的多播器(派發器):getApplicationEventMulticaster()
* 2)、multicastEvent派發事件:
* 3)、獲取到所有的ApplicationListener;
* for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
* 1)、如果有Executor,可以支援使用Executor進行非同步派發;
* Executor executor = getTaskExecutor();
* 2)、否則,同步的方式直接執行listener方法;invokeListener(listener, event);
* 拿到listener回撥onApplicationEvent方法;
三、refresh中釋出事件的階段
技巧:在onApplicationEvent方法上加斷點後,debug
首先收到ContextRefreshEvent事件,執行的時機是refresh方法的最後一個方法
// 例項化剩餘的單例bean
finishBeanFactoryInitialization();
// refresh的最後一步:釋出事件 //在他之前有initApplicationEventMulticaster();
finishRefresh();
(1)finishRefresh()
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
//釋出事件,new了一個事件 容器重新整理完成
publishEvent(new ContextRefreshedEvent(this));//容器重新整理完成,釋出了一個事件
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
(2)publishEvent
- 獲取多播器
- 多播器
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}//過載
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 {
// ***獲取到應用事件的派發器(多播器),即把這個事件傳送給多個監聽器讓他們感知//然後呼叫multicastEvent方法 派發事件
getApplicationEventMulticaster().//(1) 獲取多播器
multicastEvent(applicationEvent, eventType);//(2) 派發事件
}
// 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);
}
}
}
(3)multicastEvent
- 找到監聽器getApplicationListeners(event, type)
- 給監聽器傳送事件invokeListener(listener, event);
public class SimpleApplicationEventMulticaster
extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
@Override//派發事件
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 遍歷容器監聽器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();//如果有executor,可以利用executor進行非同步執行的話
// 可以用多執行緒方式非同步派發事件
if (executor != null) {
// 類似於執行緒池
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);//也是執行方法
}
});
}
else {//同步 方式直接執行方法
invokeListener(listener, event);
}
}
}
(4)getApplicationListeners()
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
@Nullable
private ClassLoader beanClassLoader;
@Nullable
private ConfigurableBeanFactory beanFactory;
private Object retrievalMutex = this.defaultRetriever;
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);
}
}
(5)invokeListener
// SimpleApplicationEventMulticaster;
protected void invokeListener(ApplicationListener<?> listener,//監聽器
ApplicationEvent event) {//事件
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
// 執行邏輯
doInvokeListener(listener, event);//
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
// 執行
doInvokeListener(listener, event);//
}
}
doInvokeListener
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 拿到容器物件後回撥 //如果我們自定義的邏輯,重寫的就是onApplicationEvent方法,獲得ac.close()裡也有
listener.onApplicationEvent(event);//回撥
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
}
else {
throw ex;
}
}
}
四、initApplicationEventMulticaster
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...;
try {
,,,;
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();// 初始化事件多播器
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();//註冊監聽器
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 先去容器中找
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {//"applicationEventMulticaster";
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 如果沒有多播器就new一個
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 註冊進容器中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
五、registerListeners();
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
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!
// 從容器彙總拿到所有ApplicationListener型別的bean
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 把監聽器註冊到派發器中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
六、註冊監聽方式
// 也可以@EventListener
@Service
public class UserService {
@EventListener(classes={ApplicationEvent.class})//原理:使用EventListenerMethodProcessor處理器解析方法上的@EventListener // 可以看EventListenerMethodProcessor
public void listen(ApplicationEvent event){
System.out.println("UserService。。監聽到的事件:"+event);
}
}
/*
* @see EventListenerMethodProcessor
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {
EventListenerMethodProcessor
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, //
ApplicationContextAware,
BeanFactoryPostProcessor {
public interface SmartInitializingSingleton {
/**
所有單例項bean已經建立完成
* Invoked right at the end of the singleton pre-instantiation phase,
* with a guarantee that all regular singleton beans have been created
* already. {@link ListableBeanFactory#getBeansOfType} calls within
* this method won't trigger accidental side effects during bootstrap.
* <p><b>NOTE:</b> This callback won't be triggered for singleton beans
* lazily initialized on demand after {@link BeanFactory} bootstrap,
* and not for any other bean scope either. Carefully use it for beans
* with the intended bootstrap semantics only.
*/
void afterSingletonsInstantiated();
}
SmartInitializingSingleton原理:
refresh
在finish例項化單例項bean
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 例項化單例項eban
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
...;
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
...;
}
// 例項化完了,
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
// 拿到例項化完的bean
Object singletonInstance = getSingleton(beanName);
// 判斷是否是SmartInitializingSingleton,
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();// 這裡
}
}
}
}
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
相關文章
- JMeter—監聽器(十二)JMeter
- Spring5原始碼解析-Spring框架中的事件和監聽器Spring原始碼框架事件
- Spring事件監聽機制原始碼解析Spring事件原始碼
- SpringBoot事件監聽器原始碼分析Spring Boot事件原始碼
- Spring框架(一):配置&注入&監聽器Spring框架
- flutter原始碼系列 PageView原始碼分析以及監聽事件Flutter原始碼View事件
- 【Vue2.x原始碼系列07】監聽器watch原理Vue原始碼
- Spring Boot 中動態管理 Kafka 監聽器Spring BootKafka
- Spring Data JPA中事務監聽器TransactionExecutionListenerSpring
- Spring中如何優雅的使用監聽器模式Spring模式
- spring boot 新增自定義監聽器、過濾器、攔截器Spring Boot過濾器
- Spring Boot 事件和監聽Spring Boot事件
- 深入理解Spring原始碼之IOC 擴充套件原理BeanFactoryPostProcessor和事件監聽ApplicationListenerSpring原始碼套件Bean事件APP
- 從原始碼級別深挖Zookeeper監聽機制原始碼
- Spring事件釋出與監聽Spring事件
- spring 整合kafka監聽消費SpringKafka
- 淺析Vue原始碼(八)——依賴收集與監聽Vue原始碼
- zookeeper原始碼(10)node增刪改查及監聽原始碼
- 原始碼級別的廣播與監聽實現原始碼
- PandasTA 原始碼解析(十二)AST原始碼
- 監聽器和過濾器過濾器
- spring boot 實現監聽器、過濾器、全域性異常處理Spring Boot過濾器
- vue原始碼學習:Object.defineProperty 物件屬性監聽Vue原始碼Object物件
- 直播app系統原始碼,Fragment 顯示 隱藏 監聽APP原始碼Fragment
- 事件和事件監聽器事件
- javaWeb中的監聽器JavaWeb
- 如何移除事件監聽器事件
- spring boot學習(3): SpringApplication 事件監聽Spring BootAPP事件
- Spring事件釋出與監聽機制Spring事件
- Spring 事件監聽機制及原理分析Spring事件
- Spring筆記(7) - Spring的事件和監聽機制Spring筆記事件
- Spring原始碼分析——搭建spring原始碼Spring原始碼
- Springboot中自定義監聽器Spring Boot
- day25-Listener監聽器
- jmeter監聽器(Transactions per Second)JMeter
- SpringBoot 攔截器、過濾器、監聽器Spring Boot過濾器
- 過濾器和監聽器總結過濾器
- 監聽 watch props物件屬性監聽 或深度監聽物件