美文网首页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