@EventListener注解 -【Spring底层原理】

Spring框架底层原理 专栏收录该内容
17 篇文章 0 订阅

目录

 

一、注解用法

二、实例分析

三、源码分析

四、总结


 

上篇我们讲到实现事件监听可以使用实现ApplicationListener接口 Spring中ApplicationListener -【Spring底层原理】,如果有多个方法需要监听事件,那岂不是每个方法都要放在类中实现ApplicationListener接口,这样并不是很方便,所以spring为我们提供了另外一种方式实现事件监听:使用@EventListener注解

一、注解用法

注解源码如下,有如下作用:

  • 可以作用在方法
  • 参数可以是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来进行处理的,后面会分析其源码。

二、实例分析

// 启动测试类
@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

三、源码分析

上面讲到是使用EventListenerMethodProcessor这个处理器来解析方法上的EventListener注解,点进EventListenerMethodProcessor查看,发现实现了SmartInitializingSingleton接口,主要就是通过该接口实现的。

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方法,类似于ContextRefreshedEvent

我们在afterSingletonsInstantiated方法上打上断点,看看源码是何时调用该方法执行的。

image-20210324144953217

通过方法调用栈,容器创建对象,调用refresh()方法刷新容器——>finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的单实例bean

  • 创建所有的单实例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();
      }
   }
}

四、总结

  1. IOC容器创建对象并refresh刷新
  2. finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的单实例bean
    1. 创建所有的单实例bean
    2. 获取所有创建好的单实例bean,判断各bean是否是SmartInitializingSingleton类型的
    3. 如果是则调用afterSingletonsInstantiated方法
  • 0
    点赞
  • 1
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值