@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方法
相关文章
相关标签/搜索