2、监听器模式

我的未来我决定 提交于 2020-02-26 07:27:03
当在IDEA中点击Download Sources时报错cannot download sources,解决办法,在Terminal中输入
mvn dependency:resolve -Dclassifier=sources
参考:https://www.cnblogs.com/wwjj4811/p/10364580.html
系统运行到某些关键节点时,会通过广播发布一些事件,而系统中存在一些监听器对这些事件感兴趣,会监听到这些事件,从而触发某种行为

1.1、监听器加入SpringBoot容器

@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

// 走到SpringApplication的构造函数,这边代码第一节也分析过
public SpringApplication(ResourceLoader resourceLoader, Class<!--?--> primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet&lt;&gt;(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 获取spring.factories中配置的初始化器,这边获取时也将监听器等也获取了,并放入缓存中
    setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 这边步骤同获取初始化器步骤,也是通过SpringFactoriesLoader读取,由于已经获取过,直接从缓存取
    // 下图是SpringBoot默认配置的监听器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}

1.2、发布事件

SpringBoot在容器的关键节点会发布一些事件,上图是SpringBoot的事件发布顺序
1) 框架启动时会发出starting事件,框架一启动就发出
2) 接着会在环境准备好之后发出一个environmentPrepared事件,代表SpringBoot已经把系统属性以及我们指定的一些属性加载完毕
3) 接着发出一个contextInitialized事件,表示SpringBoot上下文已经准备好,是在加载任何Bean定义之前发布
4) 接着发送一个prepared事件,表示SpringBoot应用上下文已经创建完成,但是bean还没有完全加载完成
5) 发送started事件,表示SpringBoot已经将单例的bean完成了,但是还没有调用ApplicationRunner和CommandLineRunner两个扩展接口,
   这两个接口后面分析
6) 发送ready事件,在上述两个扩展接口调用之后,发布该事件
7) SpringBoot容器出现失败,发送failed事件
// SpringApplicationRunListener中定义了发布上述事件的方法,通过该接口将发布事件的方法暴露出来,从而隐藏了具体实现
public interface SpringApplicationRunListener {

	/**
	 * Called immediately when the run method has first started. Can be used for very
	 * early initialization.
	 */
	void starting();

	/**
	 * Called once the environment has been prepared, but before the
	 * {@link ApplicationContext} has been created.
	 * @param environment the environment
	 */
	void environmentPrepared(ConfigurableEnvironment environment);

	/**
	 * Called once the {@link ApplicationContext} has been created and prepared, but
	 * before sources have been loaded.
	 * @param context the application context
	 */
	void contextPrepared(ConfigurableApplicationContext context);

	/**
	 * Called once the application context has been loaded but before it has been
	 * refreshed.
	 * @param context the application context
	 */
	void contextLoaded(ConfigurableApplicationContext context);

	/**
	 * The context has been refreshed and the application has started but
	 * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
	 * ApplicationRunners} have not been called.
	 * @param context the application context.
	 * @since 2.0.0
	 */
	void started(ConfigurableApplicationContext context);

	/**
	 * Called immediately before the run method finishes, when the application context 
	 * has been refreshed and all {@link CommandLineRunner CommandLineRunners} and
	 * {@link ApplicationRunner ApplicationRunners} have been called.
	 * @param context the application context.
	 * @since 2.0.0
	 */
	void running(ConfigurableApplicationContext context);

	/**
	 * Called when a failure occurs when running the application.
	 * @param context the application context or {@code null} if a failure occurred 
	 * before the context was created
	 * @param exception the failure
	 * @since 2.0.0
	 */
	void failed(ConfigurableApplicationContext context, Throwable exception);
}
// SpringBoot在容器的关键节点会发布一些事件
// run方法时SpringBoot的核心方法,删除部分无关代码
public ConfigurableApplicationContext run(String... args) {
  // 步骤1) 
  SpringApplicationRunListeners listeners = getRunListeners(args);
  // 步骤2) 框架已启动就发布starting事件
  listeners.starting();
  try {
     context = createApplicationContext();
     prepareContext(context, environment, listeners, applicationArguments,printedBanner);
     refreshContext(context);
     afterRefresh(context, applicationArguments);
     return context;
  }
}

1.2.1、步骤1

// 步骤1) 
SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {
    // types是待会获取EventPublishingRunListener构造函数的参数
    Class<!--?-->[] types = new Class<!--?-->[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class,
									         types, this, args));
}

// 这边代码第一节已经分析过了,通过SpringFactoriesLoader获取指定Type的实现类,并实例化
private <t> Collection<t> getSpringFactoriesInstances(Class<t> type, 
                                                      Class<!--?-->[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // 通过SpringFactoriesLoader获取指定Type的实现类,这边获取SpringApplicationRunListener的       
    // 实现类是EventPublishingRunListener,它也是SpringBoot暴露出来的用于事件发布的类
    Set<string> names = new LinkedHashSet&lt;&gt;(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 将EventPublishingRunListener实例化
    List<t> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

// 上述实例化EventPublishingRunListener时,会通过反射调用其构造函数
public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    // application.getListeners获取的就是通过SpringFactoriesLoader获取的,在步骤2.1)节已经分析
    for (ApplicationListener<!--?--> listener : application.getListeners()) {
        this.initialMulticaster.addApplicationListener(listener);
    }
}

public void addApplicationListener(ApplicationListener<!--?--> listener) {
    synchronized (this.retrievalMutex) {
        // Explicitly remove target for a proxy, if registered already,
        // in order to avoid double invocations of the same listener.
        Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
        if (singletonTarget instanceof ApplicationListener) {
            this.defaultRetriever.applicationListeners.remove(singletonTarget);
        }
        // 加入到this.defaultRetriever.applicationListeners,后面会用到
        this.defaultRetriever.applicationListeners.add(listener);
        this.retrieverCache.clear();
    }
}

1.2.2、发布事件

// 步骤2) 框架已启动就发布starting事件
listeners.starting();

public void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        // 这边的listener就是EventPublishingRunListener,通过它来发布事件
        listener.starting();
    }
}

@Override
public void starting() {
    // 发布容器启动事件
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

@Override
public void multicastEvent(ApplicationEvent event) {
    // 参数2是解析事件类型
    multicastEvent(event, resolveDefaultEventType(event));
}

@Override
public void multicastEvent(final ApplicationEvent event,
                           @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 没有配置,默认为null
    Executor executor = getTaskExecutor();
    // 步骤a) 获取哪些监听器对这个事件感兴趣
    for (ApplicationListener<!--?--> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -&gt; invokeListener(listener, event));
        }
        else {
            // 步骤b) 走这边
            invokeListener(listener, event);
        }
    }
}
// 步骤a) 获取哪些监听器对这个事件感兴趣
protected Collection<applicationlistener<?>&gt; getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
    // 获取事件源,这里是SpringApplication
    Object source = event.getSource();
    Class<!--?--> sourceType = (source != null ? source.getClass() : null);
    // 根据事件类型和事件源构造缓存key
    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();
    }

    // beanClassLoader为null,走这个分支
    if (this.beanClassLoader == null ||
        (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &amp;&amp;
         (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);
            // 获取listeners并放入retriever,下面分析这个步骤
            Collection<applicationlistener<?>&gt; listeners =
                retrieveApplicationListeners(eventType, sourceType, retriever);
            this.retrieverCache.put(cacheKey, retriever);
            return listeners;
        }
    }
    else {
        // No ListenerRetriever caching -&gt; no synchronization necessary
        return retrieveApplicationListeners(eventType, sourceType, null);
    }
}
private Collection<applicationlistener<?>&gt; retrieveApplicationListeners(ResolvableType eventType, 
				           @Nullable Class<!--?--> sourceType, @Nullable ListenerRetriever retriever) {
    List<applicationlistener<?>&gt; allListeners = new ArrayList&lt;&gt;();
    Set<applicationlistener<?>&gt; listeners;
    Set<string> listenerBeans;
    synchronized (this.retrievalMutex) {
        // 这边在2.2.1、步骤1分析到了,就是SpringBoot默认配置的一些监听器
        listeners = new LinkedHashSet&lt;&gt;(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet&lt;&gt;(this.defaultRetriever.applicationListenerBeans);
    }
    // 依此遍历每个监听器,判断该监听器是否对该事件感兴趣
    for (ApplicationListener<!--?--> listener : listeners) {
        // 关键方法,下面分析这里
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                retriever.applicationListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }
    if (!listenerBeans.isEmpty()) {
        // 默认为空,删掉这边分析
    }
    // 对listeners排序
    AnnotationAwareOrderComparator.sort(allListeners);
    if (retriever != null &amp;&amp; retriever.applicationListenerBeans.isEmpty()) {
        retriever.applicationListeners.clear();
        retriever.applicationListeners.addAll(allListeners);
    }
    return allListeners;
}
protected boolean supportsEvent(ApplicationListener<!--?--> listener, ResolvableType eventType, 
								 @Nullable Class<!--?--> sourceType) {
    // 判断是否是GenericApplicationListener,如果不是包装为GenericApplicationListenerAdapter
    GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
                                                                 (GenericApplicationListener) listener : 
                                                                            new GenericApplicationListenerAdapter(listener));
    // 正式判断是否对该事件感兴趣,分为两步supportsEventType和supportsSourceType
    return (smartListener.supportsEventType(eventType) &amp;&amp; smartListener.supportsSourceType(sourceType));
}

// 包装时做了两件事
public GenericApplicationListenerAdapter(ApplicationListener<!--?--> delegate) {
    Assert.notNull(delegate, "Delegate listener must not be null");
    // 获取监听器类型
    this.delegate = (ApplicationListener<applicationevent>) delegate;
    // 获取该监听器感兴趣的事件类型
    this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
@Override
public boolean supportsEventType(ResolvableType eventType) {
    // 判断是否是SmartApplicationListener,如果是,它有自己独有的supportsEventType方法,调用该方法
    // 判断是否支持
    if (this.delegate instanceof SmartApplicationListener) {
        Class<!--? extends ApplicationEvent--> eventClass = (Class<!--? extends ApplicationEvent-->) eventType.resolve();
        return (eventClass != null &amp;&amp; ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
    }
    else {
        // 如果不是,直接根据eventType判断是否是declaredEventType子类
        return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
    }
}
@Override
public boolean supportsSourceType(@Nullable Class<!--?--> sourceType) {
    // 如果不属于SmartApplicationListener,直接返回true
    // 如果是,那么判断supportsSourceType
    return !(this.delegate instanceof SmartApplicationListener) ||
                                      ((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);
}
// 步骤b) 走这边
invokeListener(listener, event);

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方法
        listener.onApplicationEvent(event);
    }
}

1.3、自定义监听器

1.3.1、方式1

@Order(1)
public class FirstListener implements ApplicationListener<applicationstartedevent> {

    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("hello first");
    }
}
// 在resources目录下的META-INF/spring.factories文件中配置,监听器配置同初始化器
org.springframework.context.ApplicationListener=com.lwh.springboot.listener.FirstListener

1.3.2、方式2

@Order(2)
public class SecondListener implements ApplicationListener<applicationstartedevent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("hello second");
    }
}
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
         //测试SecondInitializer时用这种启动方式,手动添加
         SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
         springApplication.addListeners(new SecondListener());
         springApplication.run(args);
    }
}

1.3.3、方式3

@Order(3)
public class ThirdListener implements ApplicationListener<applicationstartedevent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("hello third");
    }
}
// 在application.properties中配置
context.listener.classes=com.lwh.springboot.listener.ThirdListener
// 在application.properties中配置被加入SpringBoot的原理分析
其中有一个DelegatingApplicationListener,这个listener会获取application.properties中的context.listener.classes属性,
将其加入listeners集合中

1.3.4、方式4

@Order(4)
public class FourthListener implements SmartApplicationListener {
    @Override
    public boolean supportsEventType(Class<!--? extends ApplicationEvent--> eventType) {
        return ApplicationStartedEvent.class.isAssignableFrom(eventType) || 
               ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("hello fourth");
    }
}
添加方式同前面三种

1.4、面试题

1、介绍下监听器模式
2、SpringBoot关于监听器相关的实现类有哪些?
3、SpringBoot框架有哪些事件以及他们的顺序?
4、介绍下监听事件的触发机制
5、如何自定义实现系统监听器及注意事项
6、实现ApplicationListener接口与SmartApplicationListener接口区别
   ApplicationListener只能指定一个感兴趣的事件,而SmartApplicationListener定义了supportsEventType方法,可以指定多个感兴趣的事件,
   也定义了supportsSourceType方法,可以指定事件源
````</applicationstartedevent></applicationstartedevent></applicationstartedevent></applicationevent></string></applicationlistener<?></applicationlistener<?></applicationlistener<?></applicationlistener<?></applicationlistener<?></t></string></t></t></t>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!