• 【细读经典】springBoot源码(一)创建SpringApplication


    仅做源码解析,目前先省略掉搭建部分,互联网上有大量的搭建教程。当前springboot版本为2.7.x,其他版本可能稍有不同。
    我们先来看一下核心的SpringApplication类,在java/org/springframework/boot/SpringApplication.java下,在类注释之上简要阐述了当前类的作用,以及最核心的SrpingApplication.run方法的使用。简单的翻译一下:

    /**
    * Class that can be used to bootstrap and launch a Spring application from a Java main
    * method. By default class will perform the following steps to bootstrap your
    
    * application:
    * 这个class的方法能够用于引导和启动Spring应用,
    * 默认的class将会执行下面的步骤进行引导应用 *
    * 
      *
    • Create an appropriate {@link ApplicationContext} instance (depending on your * classpath)
    • *
    • Register a {@link CommandLinePropertySource} to expose command line arguments as * Spring properties
    • *
    • Refresh the application context, loading all singleton beans
    • *
    • Trigger any {@link CommandLineRunner} beans
    • *
    * 1。创建适当ApplicationContext的实例(依赖于你的classpath) * 2。注册CommandLinePropertySource并添加命令行参数到spring属性中 * 3。刷新整个应用上下文,加载所有的单实例bean * 4。触发所有的CommandLineRunner beans * * In most circumstances the static {@link #run(Class, String[])} method can be called * directly from your {@literal main} method to bootstrap your application: * 更多的情况在静态的方法run中可以看到,在你的应用中使用run来进行引导 *
    * @Configuration
    * @EnableAutoConfiguration
    * public class MyApplication  {
    *
    *   // ... Bean definitions
    *
    *   public static void main(String[] args) {
    *     SpringApplication.run(MyApplication.class, args);
    *   }
    * }
    * 
    * *

    * For more advanced configuration a {@link SpringApplication} instance can be created and * customized before being run: * 更多的配置,你可以创建SpringApplication实例进行自定义 * *

    * public static void main(String[] args) {
    *   SpringApplication application = new SpringApplication(MyApplication.class);
    *   // ... customize application settings here
    *   application.run(args)
    * }
    * 
    * * {@link SpringApplication}s can read beans from a variety of different sources. It is * generally recommended that a single {@code @Configuration} class is used to bootstrap * your application, however, you may also set {@link #getSources() sources} from: *
      *
    • The fully qualified class name to be loaded by * {@link AnnotatedBeanDefinitionReader}
    • *
    • The location of an XML resource to be loaded by {@link XmlBeanDefinitionReader}, or * a groovy script to be loaded by {@link GroovyBeanDefinitionReader}
    • *
    • The name of a package to be scanned by {@link ClassPathBeanDefinitionScanner}
    • *
    * * Configuration properties are also bound to the {@link SpringApplication}. This makes it * possible to set {@link SpringApplication} properties dynamically, like additional * sources ("spring.main.sources" - a CSV list) the flag to indicate a web environment * ("spring.main.web-application-type=none") or the flag to switch off the banner * ("spring.main.banner-mode=off"). * * @author Phillip Webb * @author Dave Syer * @author Andy Wilkinson * @author Christian Dupuis * @author Stephane Nicoll * @author Jeremy Rickard * @author Craig Burke * @author Michael Simons * @author Madhura Bhave * @author Brian Clozel * @author Ethan Rubinson * @author Chris Bono * @since 1.0.0 * @see #run(Class, String[]) * @see #run(Class[], String[]) * @see #SpringApplication(Class...) */
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    包含了大概介绍了启动流程springapplication启动流程,还有加载属性的加载器,最后提到了可以在启动的时候进行动态配置文件的配置。
    启动流程比较重要贴在下面:

    • 1.创建适当ApplicationContext的实例(依赖于你的classpath)
    • 2.注册CommandLinePropertySource并添加命令行参数到spring属性中
    • 3.刷新整个应用上下文,加载所有的单实例bean
    • 4.触发所有的CommandLineRunner beans
      接下来转到注释中多次提到的SpringApplication.run方法
    /**
    * A basic main that can be used to launch an application. This method is useful when
    * application sources are defined via a {@literal --spring.main.sources} command line
    * argument.
    * 这个基础的bean,可以启动一个应用,这个方法通常情况下应用的资源定义通过spring.main.sources命令行参数
    * 

    * Most developers will want to define their own main method and call the * {@link #run(Class, String...) run} method instead. * @param args command line arguments * @throws Exception if the application cannot be started * @see SpringApplication#run(Class[], String[]) * @see SpringApplication#run(Class, String...) */ public static void main(String[] args) throws Exception { SpringApplication.run(new Class[0], args); } /** * Static helper that can be used to run a {@link SpringApplication} from the * specified sources using default settings and user supplied arguments. * @param primarySources the primary sources to load * @param args the application arguments (usually passed from a Java main method) * @return the running {@link ApplicationContext} */ public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    注意看这里,写了theprimary sources to load,表示主要资源的加载位置
    这时候我们发现,当前的SpringApplicaroin.run被拆分成了两个步骤,第一步new SpringApplication(primarySources),在实例化后,在调用非静态的run(args)方法进行初始化,先看new SpringApplication(primarySources)

    /**
    * Create a new {@link SpringApplication} instance. The application context will load
    * beans from the specified primary sources (see {@link SpringApplication class-level}
    * documentation for details). The instance can be customized before calling
    * {@link #run(String...)}.
    * @param primarySources the primary bean sources
    * @see #run(Class, String[])
    * @see #SpringApplication(ResourceLoader, Class...)
    * @see #setSources(Set)
    */
    public SpringApplication(Class... primarySources) {
        this(null, primarySources);
    }
    
    /**
    * Create a new {@link SpringApplication} instance. The application context will load
    * beans from the specified primary sources (see {@link SpringApplication class-level}
    * documentation for details). The instance can be customized before calling
    * {@link #run(String...)}.
    * @param resourceLoader the resource loader to use
    * @param primarySources the primary bean sources
    * @see #run(Class, String[])
    * @see #setSources(Set)
    */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
        	//默认是赋值为null
    		this.resourceLoader = resourceLoader;
    		//断言检测class是不是null
    		Assert.notNull(primarySources, "PrimarySources must not be null");
    		//将class变成一个LinkedHashSet
    		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    		//判断当前的web类型,正常来说一定返回SERVLET
    		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    		//创建BootstrapRegistryInitializer
    		this.bootstrapRegistryInitializers = new ArrayList<>(
    				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    		//创建ApplicationContextInitializer
    		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    		//创建ApplicationListener
    		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    		//设置当前的main所在的class
    		this.mainApplicationClass = deduceMainApplicationClass();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    我们可以看到只有两个有参数构造器,我们默认调用的是只有一个参数的构造器,最终调用的是SpringApplication(ResourceLoader resourceLoader, Class… primarySources),第一参数可以自定义一个资源加载器,第二个参数为当前的启动类,

  • 相关阅读:
    jvm 三 之堆与栈
    FastJSON错误Could not read JSON: Unrecognized field
    【一】Mac 本地部署大模型
    怎么给视频加配音?试试这些制作方法吧
    java spring cloud 企业工程管理系统源码+二次开发+定制化服务
    NextJs 数据篇 - 数据获取 | 缓存 | Server Actions
    前端技术面试核心问题(持续更新)
    Android系统10 RK3399 init进程启动(三十一) SeAndroid实战之定义策略
    AJAX---Axios异步框架、JSON
    分布式文件系统和对象存储魔力象限,右上角都有谁?
  • 原文地址:https://blog.csdn.net/weixin_42842069/article/details/128209325