由于目前大部分都是使用 springBoot 开箱即用的开发模式,省略了复杂的配置过程。因此记录学习一下 springBoot 启动的过程。springBoot 启动的入口在 SpringApplication.run(Class<?> primarySource, String... args) 这个方法,跟进之后发现创建了一个 SpringApplication 对象并调用了它的 run 方法。

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

跟进 SpringApplication 的构造器:

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

上面的 WebApplicationType.deduceFromClasspath() 方法解析了当前的环境类型,为后面构造环境做好了准备。主要是依据当前项目中有没有 org.springframework.web.reactive.DispatcherHandler、 org.springframework.web.servlet.DispatcherServlet、javax.servlet.Servlet 这几个类来做判断,本文中我们以 web 环境作为演示,即环境的类型为 SERVLET。上面调用了两次 getSpringFactoriesInstances 这个方法,以设置 SrpingApplication 中的 initializers 和 listeners 属性。进入这个方法中:

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }

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

这里重点关注一下 SpringFactoriesLoader.loadFactoryNames(type, classLoader) 这个方法,使用 classLoader 去读取 FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories" 这个文件的内容,并封装成键值对,然后以 type 为 key 获取一个集合。因此在 SpringApplication 的构造器中获取了 spring.factories 中的 initializers 和 listeners。
接下来就会进入 SpringApplication 的 run 方法,该方法中包含了 springBoot 所有的启动流程:

    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        // step1.   获取监听器
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //启动监听器
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //step2. 环境准备
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            //step2. 创建容器
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

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

下面就比较重要的步骤做解析:

  1. 获取并启动监听器
Step1. 获取监听器并启动:

这里同样适用 getSpringFactoriesInstances 方法获取到配置文件中默认的监听器并将之以参数传入,新建了一个 SpringApplicationRunListeners 对象,这个包含了一个 EventPublishingRunListener 属性,这个属性封装了之前获取的多个监听器。其 strting 方法发布了一个 ApplicationStartingEvent 事件。这里涉及到了spring 的事件监听模式:
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

根据事件类型找到相应的监听器,并调用监听器上的 onApplicationEvent 方法。


jiao个朋友
4 声望0 粉丝