小言_互联网的博客

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

296人阅读  评论(0)

仅做源码解析,目前先省略掉搭建部分,互联网上有大量的搭建教程。当前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将会执行下面的步骤进行引导应用 *
* <ul>
* <li>Create an appropriate {@link ApplicationContext} instance (depending on your
* classpath)</li>
* <li>Register a {@link CommandLinePropertySource} to expose command line arguments as
* Spring properties</li>
* <li>Refresh the application context, loading all singleton beans</li>
* <li>Trigger any {@link CommandLineRunner} beans</li>

* </ul>

* 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来进行引导 * <pre class="code">
* &#064;Configuration
* &#064;EnableAutoConfiguration
* public class MyApplication  {
*
*   // ... Bean definitions
*
*   public static void main(String[] args) {
*     SpringApplication.run(MyApplication.class, args);
*   }
* }
* </pre>
*
* <p>
* For more advanced configuration a {@link SpringApplication} instance can be created and

* customized before being run:
* 更多的配置,你可以创建SpringApplication实例进行自定义 *
* <pre class="code">
* public static void main(String[] args) {
*   SpringApplication application = new SpringApplication(MyApplication.class);
*   // ... customize application settings here
*   application.run(args)
* }
* </pre>
*
* {@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:
* <ul>
* <li>The fully qualified class name to be loaded by
* {@link AnnotatedBeanDefinitionReader}</li>
* <li>The location of an XML resource to be loaded by {@link XmlBeanDefinitionReader}, or
* a groovy script to be loaded by {@link GroovyBeanDefinitionReader}</li>
* <li>The name of a package to be scanned by {@link ClassPathBeanDefinitionScanner}</li>
* </ul>
*
* 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命令行参数
* <p>
* 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) {
    	//默认是赋值为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();
}

 

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


转载:https://blog.csdn.net/weixin_42842069/article/details/128209325
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场