@EventListener註解 -【Spring底層原理】

blog59

上篇咱們講到實現事件監聽可使用實現ApplicationListener接口 Spring中ApplicationListener -【Spring底層原理】,若是有多個方法須要監聽事件,那豈不是每一個方法都要放在類中實現ApplicationListener接口,這樣並非很方便,因此spring爲咱們提供了另一種方式實現事件監聽:使用@EventListener註解java

1、註解用法

註解源碼以下,有以下做用:spring

  • 能夠做用在方法
  • 參數能夠是class數組,能夠寫多個事件
  • 使用了該註解的方法,當容器中發佈事件後,該方法會觸發,相似實現ApplicationListener接口
/* * @author Stephane Nicoll * @author Sam Brannen * @since 4.2 * @see EventListenerMethodProcessor */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {

	@AliasFor("classes")
	Class<?>[] value() default {};

	@AliasFor("value")
	Class<?>[] classes() default {};

	String condition() default "";
}
複製代碼

從註釋能夠看到是使用EventListenerMethodProcessor這個處理器來解析方法上的EventListener註解,EventListenerMethodProcessor主要則是經過其實現的接口SmartInitializingSingleton來進行處理的,後面會分析其源碼。bootstrap

2、實例分析

// 啓動測試類
@Test
public void TestMain(){
    // 建立IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    // 本身發佈一個事件
    applicationContext.publishEvent(new ApplicationEvent("本身發佈的事件") {
    });
    applicationContext.close();
}

// 事件觸發
@Service
public class UserService {
    // 當容器中發佈事件後,該方法會觸發
    @EventListener(classes = {ApplicationEvent.class})
    public void listener1(ApplicationEvent event){
        System.out.println("監聽到的事件1:" + event);
    }
    @EventListener(classes = {ApplicationEvent.class})
    public void listener2(ApplicationEvent event){
        System.out.println("監聽到的事件2:" + event);
    }
}

// 配置類
@ComponentScan("listener")
@Configuration
public class AppConfig {
}
複製代碼

運行啓動類,能夠看到,兩個事件都被觸發了,使用@EventListener註解,方便讓多個方法觸發數組

image-20210324135958362

3、源碼分析

上面講到是使用EventListenerMethodProcessor這個處理器來解析方法上的EventListener註解,點進EventListenerMethodProcessor查看,發現實現了SmartInitializingSingleton接口,主要就是經過該接口實現的。markdown

public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {}
複製代碼
public interface SmartInitializingSingleton {

   /** * 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接口有個afterSingletonsInstantiated方法,當單實例bean所有建立完成,會觸發這個接口,執行afterSingletonsInstantiated方法,相似於ContextRefreshedEventapp

咱們在afterSingletonsInstantiated方法上打上斷點,看看源碼是什麼時候調用該方法執行的。ide

image-20210324144953217

經過方法調用棧,容器建立對象,調用refresh()方法刷新容器——>finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的單實例beanoop

  • 建立全部的單實例bean
  • 獲取全部建立好的單實例bean,判斷各bean是不是SmartInitializingSingleton類型的
  • 若是是則調用afterSingletonsInstantiated方法

這裏便到了咱們上面分析的SmartInitializingSingleton#afterSingletonsInstantiated方法,也就是@EventListener註解註解起做用的地方源碼分析

@Override
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);

   // 遍歷beanName,建立bean,即非懶加載單實例bean的初始化
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               FactoryBean<?> factory = (FactoryBean<?>) bean;
               boolean isEagerInit;
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                  isEagerInit = AccessController.doPrivileged(
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {
            // 建立對象
            getBean(beanName);
         }
      }
   }

   // Trigger post-initialization callback for all applicable beans...
   // 建立完bean後判斷各bean是否實現了SmartInitializingSingleton,若是是則執行 smartSingleton.afterSingletonsInstantiated()方法
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
               .tag("beanName", beanName);
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               // 執行afterSingletonsInstantiated
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
         smartInitialize.end();
      }
   }
}
複製代碼

4、總結

  1. IOC容器建立對象並refresh刷新
  2. finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的單實例bean
    1. 建立全部的單實例bean
    2. 獲取全部建立好的單實例bean,判斷各bean是不是SmartInitializingSingleton類型的
    3. 若是是則調用afterSingletonsInstantiated方法
相關文章
相關標籤/搜索