SpringBoot源码解析(二)事件发布机制

上篇文章从springboot应用的启动开始说起,分析完了SpringApplication对象的初始化流程

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

这篇文章开始分析后面的run方法

    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

限于篇幅,本篇主要分析到这行listeners.starting结束,也就是先简单介绍下springboot初始化过程的事件发布机制,以及在springboot项目开始启动时候的一个扩展点
在这里插入图片描述
前面的StopWatch主要是记录下启动的时间,调用start就会获取系统时间赋给startTime,结束的时候再调下stop,计算系统启动耗时;
this.configureHeadlessProperty()主要是设置启动模式为headless,在缺少外接设备(显示屏、键盘)等的环境启动
这些都不是重点,我们主要关注有关listener的两行代码

    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();

首先进入getRunListeners方法

    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }

可以看到一个熟悉的方法getSpringFactoriesInstances,上篇文章我们分析过,这个方法的主要作用就是从META-INF/spring.factories中找到指定类型(这里即SpringApplicationRunListener)的实现,并实例化,只是不同的是,这里传入了一个class[],并指定了参数,也就是指定了实例化时要调用的有参构造器,第一个参数就是上篇文章着重介绍的SpringApplication对象,第二个参数是args,也就是main方法的入参

通过debug,发现在spring.factories中,只加载到了一个,具体类型为EventPublishingRunListener
在这里插入图片描述
位置在spring-boot下的META-INF/spring.factories中
在这里插入图片描述
进入这个类,先观察下它指定的构造方法

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    private final SpringApplication application;
    private final String[] args;
    private final SimpleApplicationEventMulticaster initialMulticaster;

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        Iterator var3 = application.getListeners().iterator();

        while(var3.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var3.next();
            this.initialMulticaster.addApplicationListener(listener);
        }

    }
    ......
    ......

将SpringApplication对象和启动参数存储起来,并初始化了一个事件多播器
然后调用了SpringApplication的getListeners方法,之前分析过,这个listeners中存储的就是从spring.factories文件中找到的ApplicationListener,然后添加到事件多播器中,也就是说,此时这个事件多播器中已经有了一些监听者,可以向他们发布事件了

    public void addApplicationListener(ApplicationListener<?> listener) {
        Object var2 = this.retrievalMutex;
        synchronized(this.retrievalMutex) {
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }

            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }

实例化完成后,回过头来看下这个SpringApplicationRunListeners的构造方法

    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }
    SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList(listeners);
    }

就是把找到的SpringApplicationRunListener存储在变量listeners中,目前是只有一个EventPublishingRunListener,其内部有一个事件多播器,存储了SpringAapplication对象初始化时找到的ApplicationListener列表

到此第一行结束,再看第二行listeners.starting()

    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();
    public void starting() {
        Iterator var1 = this.listeners.iterator();

        while(var1.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
            listener.starting();
        }

    }

循环listeners,调用其starting方法
这里只有一个,就可以简单看成是调用EventPublishingRunListener的starting方法
看下这个方法的实现

    public void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
    public void multicastEvent(ApplicationEvent event) {
        this.multicastEvent(event, this.resolveDefaultEventType(event));
    }

通过多播器发布了一个事件ApplicationStartingEvent,这个多播器在初始化后,就把SpringApplication中的listeners都注册给它了,然后就可以从这些listeners中,找到对当前事件感兴趣的监听者

    public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        Iterator var4 = this.getApplicationListeners(event, type).iterator();

        while(var4.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }
    }

进入getApplicationListeners方法,其中Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever) 这行代码就通过事件类型找到了匹配的监听者

    protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();
        Class<?> sourceType = source != null ? source.getClass() : null;
        AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
        AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
        if (retriever != null) {
            return retriever.getApplicationListeners();
        } else if (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
            Object var7 = this.retrievalMutex;
            synchronized(this.retrievalMutex) {
                retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
                if (retriever != null) {
                    return retriever.getApplicationListeners();
                } else {
                    retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
                    Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
                    this.retrieverCache.put(cacheKey, retriever);
                    return listeners;
                }
            }
        } else {
            return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
        }
    }

具体寻找的过程,先遍历所有的listener,调用supportEvent方法
在这里插入图片描述
supportsEvent方法的实现,如果监听器是GenericApplicationListener类型,就已经实现了supportsEventType方法,后面可以直接调用该方法判断是否支持当前事件,如果不是GenericApplicationListener类型,就把事件封装成GenericApplicationListenerAdapter,然后调用封装后的Adapter的supportsEventType方法

    protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
        GenericApplicationListener smartListener = listener instanceof GenericApplicationListener ? (GenericApplicationListener)listener : new GenericApplicationListenerAdapter(listener);
        return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType);
    }

看下封装成Adapter的逻辑,在Adapter的构造函数中,把当前的监听器赋给变量delegate ,然后通过resolveDeclaredEventType完成对监听事件类型的解析

    public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
        Assert.notNull(delegate, "Delegate listener must not be null");
        this.delegate = delegate;
        this.declaredEventType = resolveDeclaredEventType(this.delegate);
    }

resolveDeclaredEventType方法

    @Nullable
    private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
        ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
        if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
            Class<?> targetClass = AopUtils.getTargetClass(listener);
            if (targetClass != listener.getClass()) {
                declaredEventType = resolveDeclaredEventType(targetClass);
            }
        }

        return declaredEventType;
    }

调用了同名方法

    @Nullable
    static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
        ResolvableType eventType = (ResolvableType)eventTypeCache.get(listenerType);
        if (eventType == null) {
            eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric(new int[0]);
            eventTypeCache.put(listenerType, eventType);
        }

        return eventType != ResolvableType.NONE ? eventType : null;
    }

最终是通过as方法,转化为ApplicationListener并取其泛型作为事件类型
说白了就是到类的继承结构中,找到ApplicationListener< T >,取T作为要监听的事件类型

    public ResolvableType as(Class<?> type) {
        if (this == NONE) {
            return NONE;
        } else {
            Class<?> resolved = this.resolve();
            if (resolved != null && resolved != type) {
                ResolvableType[] var3 = this.getInterfaces();
                int var4 = var3.length;

                for(int var5 = 0; var5 < var4; ++var5) {
                    ResolvableType interfaceType = var3[var5];
                    ResolvableType interfaceAsType = interfaceType.as(type);
                    if (interfaceAsType != NONE) {
                        return interfaceAsType;
                    }
                }

                return this.getSuperType().as(type);
            } else {
                return this;
            }
        }
    }

比如我们自己定义一个监听器

public class MyListener implements ApplicationListener<ApplicationEvent> {

那么最终取到的就是泛型中的ApplicationEvent

然后看下这个GenericApplicationListenerAdapter的supportsEventType方法的实现

    public boolean supportsEventType(ResolvableType eventType) {
        if (this.delegate instanceof SmartApplicationListener) {
            Class<? extends ApplicationEvent> eventClass = eventType.resolve();
            return eventClass != null && ((SmartApplicationListener)this.delegate).supportsEventType(eventClass);
        } else {
            return this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType);
        }
    }

如果监听器是SmartApplicationListener类型,则调用监听器自己的supportsEventType方法,否则就看声明的事件类型(即上面ApplicationEvent< T >的类型)是否是当前事件或当前事件的父类

到此针对判断监听器是否该处理某个事件,做个小结

  • 如果监听器的类型是GenericApplicationListener类型,则直接调用它的supportsEventType方法
  • 如果不是GenericApplicationListener类型,则先包装成GenericApplicationListenerAdapter,在包装的过程中,获取类声明中的事件类型ApplicationListener< T >作为要监听的事件类型
  • 如果监听器类型是SmartApplicationListener,则调用它的supportsEventType方法
  • 判断 T 是否是当前事件或当前事件的父类

再附上一张最初的10个Listener的继承结构,以及各个监听器感兴趣的事件
在这里插入图片描述

通过supportsEventType判断支持当前事件类型后,再调用supportsSourceType方法,该方法默认返回的就是true,监听器也可以重写该方法,指定自己关注的事件源

public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
    boolean supportsEventType(ResolvableType var1);

    default boolean supportsSourceType(@Nullable Class<?> sourceType) {
        return true;
    }

    default int getOrder() {
        return 2147483647;
    }
}

通过debug,可以看到对ApplicationStartingEvent感兴趣的监听者有4个
(ApplicationStartingEvent继承自SpringApplicationEvent,而SpringApplicationEvent又继承自ApplicationEvent,结合上面分析的流程以及监听器的类图,就不难知道为什么是这4个了)

  • DelegatingApplicationListener
  • LoggingApplicationListener
  • LiquibaseServiceLocatorApplicationListener
  • BackgroundPreinitializer
    在这里插入图片描述

本文只介绍事件发布机制的大概原理,至于上面4个监听者,在ApplicationStartingEvent事件中做了哪些处理,我们后续再分析

回到之前的代码,对找到的监听者调用invokeListener,最终调用它的onApplicationEvent方法

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
            this.doInvokeListener(listener, event);
        }
    }
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        } catch (ClassCastException var6) {
            String msg = var6.getMessage();
            if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
                throw var6;
            }
            Log logger = LogFactory.getLog(this.getClass());
            if (logger.isDebugEnabled()) {
                logger.debug("Non-matching event type for listener: " + listener, var6);
            }
        }
    }

扩展点ApplicationStartingEvent

假如你想在springboot项目启动的时候,做一些初始化,就可以自己实现一个监听器,监听这个ApplicationStartingEvent的发布

比如新建一个监听者MyApplicationStartListener

public class MyApplicationStartListener implements ApplicationListener<ApplicationStartingEvent> {

    @Override
    public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
        System.out.println("=====项目开始启动=====");
        //doSomething
    }
}

然后在项目中新建/META-INF/spring.factories文件,把这个自定义的监听器配置进去
在这里插入图片描述
启动项目,可以看到在springboot项目最初启动的时候就打印了日志,这也可以看作是springboot给我们提供的一个扩展点
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值