【细读经典】springBoot源码(一)创建SpringApplication
创始人
2024-03-23 03:35:16

仅做源码解析,目前先省略掉搭建部分,互联网上有大量的搭建教程。当前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...)*/

包含了大概介绍了启动流程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);}

注意看这里,写了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) {//默认是赋值为nullthis.resourceLoader = resourceLoader;//断言检测class是不是nullAssert.notNull(primarySources, "PrimarySources must not be null");//将class变成一个LinkedHashSetthis.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//判断当前的web类型,正常来说一定返回SERVLETthis.webApplicationType = WebApplicationType.deduceFromClasspath();//创建BootstrapRegistryInitializerthis.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));//创建ApplicationContextInitializersetInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//创建ApplicationListenersetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//设置当前的main所在的classthis.mainApplicationClass = deduceMainApplicationClass();
}

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

相关内容

热门资讯

恒指牛熊街货比(59:41)︱... 截至1月7日,恒指最新的牛熊街货比例为59:41。中信证券牛熊证街货分布图中的数据显示,熊证街货重货...
北欧五国外长就格陵兰岛问题发表... 当地时间1月6日,丹麦、芬兰、冰岛、挪威和瑞典外长发表联合声明。声明称,作为北欧、北极国家及北约盟国...
英国10年期国债收益率跌2.2... 每经AI快讯,周二(1月6日)欧市尾盘,英国10年期国债收益率跌2.2个基点,报4.484%;两年期...
沈祥福、高洪波、胡建平、杨晨、... 转自:北京日报客户端1月6日,北京市足球运动协会第八届第三次会员大会在京举行,会上总结了北京足球过去...
“可办”变“智办” 城市更聪明 转自:贵州日报 贵州日报天眼新闻记者 谌思宇冬日的贵阳北站,车辆进出有序,旅客往来频繁。“人多车少的...