乐趣区

关于java:SrpingBoot-启动流程分析

因为目前大部分都是应用 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 办法。

退出移动版