【spring原始碼】十二、監聽器

hancoder發表於2020-12-20

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);
                    }
                }
            }
        }
    }

相關文章