您的当前位置:首页正文

springboot 2.0启动流程源码分析(二)

来源:要发发知识网

上一篇文章我们分析出 springboot启动的关键步骤如下所示:
1.获取并启动监听器
2.读取命令行的参数
3.构造容器环境
4.创建容器
5.实例化SpringBootExceptionReporter
6.准备容器
7.刷新容器
8.刷新容器后的扩展接口
我们先看获取并启动监听器,源码如下:

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

一、跟进getRunListeners方法:

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

通过SpringApplicationRunListeners构造函数在创建监听器

SpringApplicationRunListeners(Log log,
            Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList<>(listeners);
    }

通过getSpringFactoriesInstances来获取监听器列表

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

首先创建了一个classloader,然后用SpringFactoriesLoader.loadFactoryNames(type, classLoader),加载监听器类的列表。


image.png
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryClassName = ((String) entry.getKey()).trim();
                    for (String factoryName :  entry.getValue())) {
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

result的值如下图所示,因为result不为null,直接返回,否则会进入try块部分逻辑。


image.png

FACTORIES_RESOURCE_LOCATION="META-INF/spring.factories",
通过这里我们看到了其首先加载了META-INF/spring.factories这个配置文件下的所有资源,并放入缓存,然后通过getOrDefault(factoryClassName, Collections.emptyList())获取了org.springframework.context.SpringApplicationRunListener定义的资源列表。
这里调用层级比较深,但是我们仍然可以确定传给参数factoryClassName的值就是:SpringApplicationRunListener.class,该类对应的监听器类就如下所示:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

然后通过createSpringFactoriesInstances实例化监听器类

private <T> List<T> createSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
            Set<String> names) {
        List<T> instances = new ArrayList<>(names.size());
        for (String name : names) {
            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass
                        .getDeclaredConstructor(parameterTypes);
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException(
                        "Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }

通过Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes)可以知道getRunListeners的属性types为传递给监听器构造器的参数。
通过AnnotationAwareOrderComparator.sort(instances)对监听器类进行排序。
AnnotationAwareOrderComparator是OrderComparator的子类,用来支持Spring的Ordered类、@Order注解和@Priority注解。
二、跟进listeners.starting()方法:
逐个启动监听器

public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }

接下来我们需要跟进EventPublishingRunListener类,从名字可以看出EventPublishingRunListener类是启动事件发布监听器,主要用来发布启动事件。该类的构造函数如下

public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

然后我们看一下starting函数

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

EventPublishingRunListener这个是springBoot框架中最早执行的监听器,在该监听器执行started()方法时,会继续发布事件,也就是事件传递。这种实现主要还是基于spring的事件机制。跟进SimpleApplicationEventMulticaster的multicastEvent方法

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

这里会根据事件类型ApplicationStartingEvent获取对应的监听器

/**
     * Return a Collection of ApplicationListeners matching the given
     * event type. Non-matching listeners get excluded early.
     * @param event the event to be propagated. Allows for excluding
     * non-matching listeners early, based on cached matching information.
     * @param eventType the event type
     * @return a Collection of ApplicationListeners
     * @see org.springframework.context.ApplicationListener
     */
    protected Collection<ApplicationListener<?>> getApplicationListeners(
            ApplicationEvent event, ResolvableType eventType) {

        Object source = event.getSource();
        Class<?> sourceType = (source != null ? source.getClass() : null);
        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();
        }

        if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                        (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);
                Collection<ApplicationListener<?>> listeners =
                        retrieveApplicationListeners(eventType, sourceType, retriever);
                this.retrieverCache.put(cacheKey, retriever);
                return listeners;
            }
        }
        else {
            // No ListenerRetriever caching -> no synchronization necessary
            return retrieveApplicationListeners(eventType, sourceType, null);
        }
    }

在容器启动之后执行响应的动作,有如下4种监听器:


image.png

这是springBoot启动过程中,第一处根据类型,执行监听器的地方。根据发布的事件类型从上述10种监听器中选择对应的监听器进行事件发布,当然如果继承了 springCloud或者别的框架,就不止10个了。这里选了一个 springBoot 的日志监听器来进行讲解,核心代码如下:

@Override
    public void onApplicationEvent(ApplicationEvent event) {
        //在springboot启动的时候
        if (event instanceof ApplicationStartedEvent) {
            onApplicationStartedEvent((ApplicationStartedEvent) event);
        }
        //springboot的Environment环境准备完成的时候
        else if (event instanceof ApplicationEnvironmentPreparedEvent) {
            onApplicationEnvironmentPreparedEvent(
                    (ApplicationEnvironmentPreparedEvent) event);
        }
        //在springboot容器的环境设置完成以后
        else if (event instanceof ApplicationPreparedEvent) {
            onApplicationPreparedEvent((ApplicationPreparedEvent) event);
        }
        //容器关闭的时候
        else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
                .getApplicationContext().getParent() == null) {
            onContextClosedEvent();
        }
        //容器启动失败的时候
        else if (event instanceof ApplicationFailedEvent) {
            onApplicationFailedEvent();
        }
    }

因为我们的事件类型为ApplicationEvent,所以会执行onApplicationStartedEvent((ApplicationStartedEvent) event)。

private void onApplicationStartingEvent(ApplicationStartingEvent event) {
        this.loggingSystem = LoggingSystem
                .get(event.getSpringApplication().getClassLoader());
        this.loggingSystem.beforeInitialize();
    }

springBoot会在运行过程中的不同阶段,发送各种事件,来执行对应监听器的对应方法。大同小异,别的监听器执行流程这里不再赘述,后面会有单独的详解。

我们简单总结一下:“获取并启动监听器”这一步主要是启动了一个EventPublishingRunListener监听器,该监听器的作用就是广播ApplicationStartingEvent事件,这样跟ApplicationStartingEvent事件相关的监听器就会执行响应的动作。