aware,事件的使用

1、aware接口的使用例子

通过Aware接口、ApplicationContextAwareProcessor bean后处理器,将IOC容器中的组件在创建bean的时候通过BeanPostprocessor接口中的postProcessBeforeInitialization方法赋值到需要的地方。

有一些组件也可以通过自动注入的方式获取,具体哪些可以看IOC刷新主流程的第三步。

@Component
public class UseApplicationContext implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

后处理器关键方法

private void invokeAwareInterfaces(Object bean) {
   if (bean instanceof Aware) {
      if (bean instanceof EnvironmentAware) {
         ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
         ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
      }
      if (bean instanceof ResourceLoaderAware) {
         ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
         ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
         ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
         ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
   }
}

2、事件派发的使用例子

2.1、通过继承的方式

定义监听类,这个需要添加到容器中。这个是泛型的接口,可以指定监听感兴趣的事件源。

public class ApplicationListenerDemo implements ApplicationListener<MyApplicationEvent> {
    @Override
    public void onApplicationEvent(MyApplicationEvent event) {
        System.out.println(event);
    }
}

定义事件源

public class MyApplicationEvent extends ApplicationEvent {
    public MyApplicationEvent(Object source) {
        super(source);
    }
}

发布事件,获取应用上下文,手动发布事件

AnnotationConfigApplicationContext context = getContext(ExtConfig.class);
context.publishEvent(new MyApplicationEvent("我的事件"));

2.2、通过注解的方式

这个和上面唯一不同的就是时间监听的定义

public class ApplicationListenerAnnotationDemo {
    // classes 指定感兴趣的事件源
    @EventListener(classes = {MyApplicationEvent.class})
    public void customEvent(MyApplicationEvent event){
        System.out.println("ApplicationListenerDemo.customEvent==========="+event);
    }
}

2.3、执行过程的分析

context.publishEvent()会将事件的派发委托给IOC容器刷新中在第八步初始化好的事件派发器。默认的是SimpleApplicationEventMulticaster

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   // 找到合适的监听器遍历派发,这个就是对泛型和注解指定事件源的支持
   for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      // 异步支持,需要设置,默认的是同步
      Executor executor = getTaskExecutor();
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         // 事件派发
         invokeListener(listener, event);
      }
   }
}

事件派发,这个流程还是挺清楚的,看看有没有设置异常处理,默认无;doInvokeListener这个方法就是具体的派发实现了。

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

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
   try {
      listener.onApplicationEvent(event);
   }
   catch (ClassCastException ex) {
      String msg = ex.getMessage();
      if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
         // Possibly a lambda-defined listener which we could not resolve the generic event type for
         // -> let's suppress the exception and just log a debug message.
         Log logger = LogFactory.getLog(getClass());
         if (logger.isDebugEnabled()) {
            logger.debug("Non-matching event type for listener: " + listener, ex);
         }
      }
      else {
         throw ex;
      }
   }
}

这个地方是直接调用ApplicationListener#onApplicationEvent,第一种方式好理解。事件监听器通过bean的后处理器完成,即org.springframework.context.support.ApplicationListenerDetector#postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
   if (bean instanceof ApplicationListener) {
      // potentially not detected as a listener by getBeanNamesForType retrieval
      Boolean flag = this.singletonNames.get(beanName);
      if (Boolean.TRUE.equals(flag)) {
         // singleton bean (top-level or inner): register on the fly
         this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
      }
      else if (Boolean.FALSE.equals(flag)) {
         if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
            // inner bean with other scope - can't reliably process events
            logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
                  "but is not reachable for event multicasting by its containing ApplicationContext " +
                  "because it does not have singleton scope. Only top-level listener beans are allowed " +
                  "to be of non-singleton scope.");
         }
         this.singletonNames.remove(beanName);
      }
   }
   return bean;
}

第二种方式明明没有实现这个接口,为什么能向上转型成这个接口的类型。

这个其实看EventListener注解源码注释可以看到@see EventListenerMethodProcessor,那么这个类应该就是关键了,这个类是SmartInitializingSingleton的接口,会在所有的bean实例化完成之后执行afterSingletonsInstantiated这个方法。

这个处理的流程,遍历所有的bean;查找这个bean中所有添加了EventListener注解的方法;通过DefaultEventListenerFactory#createApplicationListener创建一个ApplicationListener并添加到事件派发器的事件监听集合。

posted @ 2020-09-01 15:12  maoyan  阅读(281)  评论(0编辑  收藏  举报