SpringBoot源码——SpringApplication对象初始化过程

本文详细解析了SpringBoot的启动过程,包括SpringApplication对象的创建、初始化及run方法的执行流程,介绍了如何加载配置文件、创建上下文环境、刷新上下文等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot的初始化过程其实是创建并初始化SpringApplication对象的过程。

先创建SpringApplication对象,然后执行run方法

创建SpringApplication对象

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        //判断SpringBoot应用的类型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //初始化classpath下所有已配置的 ApplicationListener
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));        
        //获取
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

 

 getSpringFactoriesInstances方法

  private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

loadFactoryNames方法

 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

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());
        Iterator var7 = names.iterator();

        while(var7.hasNext()) {
            String name = (String)var7.next();

            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                T instance = BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            } catch (Throwable var12) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
            }
        }

        return instances;

通过getSpringFactoriesInstances获取并设置SpringBoot上下文、监听器就完成了

执行run方法方法

public ConfigurableApplicationContext run(String... args) {
        //开始计时(计算初始化需要花费多少时间)
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        //配置java.awt.headless
        this.configureHeadlessProperty();
        // 获取spring.factories中配置的SpringApplicationRunListener实现类
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        // 发送ApplicationStartedEvent事件
        listeners.starting();

        Collection exceptionReporters;
        try {
            //命令行参数处理
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //构建Environment
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            //处理spring.beaninfo.ignore配置
            this.configureIgnoreBeanInfo(environment);
            
            Banner printedBanner = this.printBanner(environment);
            // 创建ApplicationContext
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
             //刷新前的准备
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //刷新上下文
            this.refreshContext(context);
            //刷新应用上下文后的扩展接口
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

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

通过run 方法

获取并启动监听器
构造应用上下文环境
初始化应用上下文
刷新应用上下文前的准备阶段
刷新应用上下文
刷新应用上下文后的扩展接口

### 初始化一个Spring Boot项目 #### 使用Spring Initializr脚手架创建项目 通过访问Spring官方提供的在线工具——Spring Initializr来快速构建新的Spring Boot应用。该网站提供了图形化界面让用户能够方便地选择所需的依赖项并自动生成基础工程文件[^1]。 ```bash https://start.spring.io/ ``` 在此页面上可以指定诸如Java版本、Spring Boot版本以及想要加入到新项目的各种starter dependencies等选项之后点击“Generate”,下载压缩包解压即得到完整的Maven/Gradle项目结构。 #### Maven配置中的`<parent>`节点定义继承关系 对于基于Maven管理的Spring Boot应用程序而言,在`pom.xml`中声明父POM为`spring-boot-starter-parent`是非常重要的一步操作,这不仅简化了依赖管理和插件配置还确保了最佳实践的应用[^2]: ```xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> ``` 上述代码片段展示了如何在Maven项目里引入Spring Boot作为父级模块,并指定了具体的版本号以便于后续开发过程中保持一致性和兼容性。 #### 添加必要的Starter Dependencies 为了使新建的Spring Boot项目具备Web功能或其他特性,则需向其添加对应的Starters。例如要实现RESTful Web服务可添加如下dependency至`pom.xml`内: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> ``` 此部分描述了怎样利用特定的启动器(如web starter)来增强应用程序的功能集,而无需手动处理复杂的库集成工作。 #### 编写入口类与核心注解@SpringBootApplication 最后,在src/main/java路径下建立主程序入口类MainApplication.java, 并在其顶部加上`@SpringBootApplication`注释以激活自动配置机制和其他默认行为: ```java package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 这段源码体现了最简单形式下的Spring Boot Hello World案例,其中包含了整个框架的核心组件初始化逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值