美文网首页SpringBoot系列
3) SpringApplication源码分析

3) SpringApplication源码分析

作者: 涣涣虚心0215 | 来源:发表于2021-02-20 17:07 被阅读0次

上一篇分析了@SpringBootApplication注解,接下来分析SpringApplication。

@SpringBootApplication
public class ExceptionApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExceptionApplication.class, args);
    }
}
public static ConfigurableApplicationContext run(Class<?> primarySource,
        String... args) {
    return run(new Class<?>[] { primarySource }, args);
}
//这里内部实例化SpringApplication,并调用它的run()方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
        String[] args) {
    return new SpringApplication(primarySources).run(args);
}

SpringApplication构造方法

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //primarySources就是启动类的class
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //获取application的类型,这里基本是servlet
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //设置Initializers,通过SpringFactoriesLoader获取ApplicationContextInitializer的相关配置类
    setInitializers((Collection) getSpringFactoriesInstances(
            ApplicationContextInitializer.class));
    //设置Listener,通过SpringFactoriesLoader获取ApplicationListener的相关配置类
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //推断MainApplicationClass
    this.mainApplicationClass = deduceMainApplicationClass();
}
//getSpringFactoriesInstances内部使用SpringFactoriesLoader来加载spring.factory下面配置的类名
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;
}
//获得完类名之后加载该类,并实例化该类
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;
}

run()方法

run()方法返回的是ConfigurableApplicationContext 。
那么内部主要逻辑就是创建AnnotationConfigServletWebServerApplicationContext以及ConfigurableEnvironment环境的准备(Environment主要与PropertySource以及activeProfile相关),最后调用applicationContext的refresh()方法。

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    //定义引用ConfigurableApplicationContext
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    //设置system property:java.awt.headless
    configureHeadlessProperty();
    //观察者模式,获取所有的SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //调用runListener的starting方法,表示开始start
    listeners.starting();
    try {
        //内部创建了CommandLinePropertySource,即命令行传进来的参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
        //准备environment
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        //打印banner
        Banner printedBanner = printBanner(environment);
        //创建ApplicationContext:AnnotationConfigServletWebServerApplicationContext
        context = createApplicationContext();
        //通过SpringFactoriesLoader获取SpringBootExceptionReporter相关的类
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        //准备applicationContext
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
        //调用applicationContext的refresh()核心方法
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        //通知观察者已经启动完成
        listeners.started(context);
        //调用ApplicationRunner以及CommandLineRunner
        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;
}
//准备ConfigurableEnvironment
private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // Create and configure the environment.
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //调用listener的environmentPrepared方法
    listeners.environmentPrepared(environment);
    //将environment绑定到SpringApplication
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader())
                .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}
//推断主类,这里很讨巧的使用RuntimeException的StackTraceElement来加载主类
private Class<?> deduceMainApplicationClass() {
    try {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

相关文章

网友评论

    本文标题:3) SpringApplication源码分析

    本文链接:https://www.haomeiwen.com/subject/gnmaxltx.html