【分布式&微服务】SpringBoot启动原理

一、SpringBoot启动类

@SpringBootApplication(exclude= DataSourceAutoConfiguration.class)
public class PracticeApplication {
    public static void main(String[] args) {
        SpringApplication.run(PracticeApplication.class, 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);
	}

整体流程如下:
在这里插入图片描述

2-1 创建SpringApplication对象


	/**
	 * 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) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		// 将启动类放入primarySources
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 获取应用的类型:servlet或者是webFlux
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 从spring.factories 中去获取所有key:org.springframework.context.ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		// 去spring.factories 中去获取所有key: org.springframework.context.ApplicationListener
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 从Application找到main方法所在的那个类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

基本流程:
1.获取启动类;
2.获取web应用类型;
3.从spring.factories中读取对外扩展的ApplicationContextInitializer ,ApplicationListener;
4.根据main方法找出所在类。

2-2 SpringApplication.run()


	/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		// 1.获取所有的SpringApplicationRunListeners,调用它们的starting()方法,通知它们当前SpringBoot应用即将启动
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
		    // 2.配置当前应用将要使用的Environment,遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,通知它们当前SpringBoot应用使用的Environment准备好了
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			// 3.如果SpringApplication的showBanner属性被设置为true,则打印banner(横幅)
			Banner printedBanner = printBanner(environment);
			// 4.创建ApplicationContext上下文对象(利用反射)
			// 例如:servlet项目:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2a32fb6
			context = createApplicationContext();
			// 5. 遍历调用所有SpringApplicationRunListener的contextPrepared()方法
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// 6.调用ApplicationContext的refresh()方法,将所有的BeanDefinition转化为Bean对象放置于IOC容器中
			refreshContext(context);
			// protected方法,用户可去实现自己的逻辑
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) { // 默认为true
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			// 7.调用SpringApplicationRunListeners的started()方法,将所有的监听器进行开启
			listeners.started(context);
			// 8.查找当前ApplicationContext中是否注册有ApplicationRunner或者CommandLineRunner,如果有,则遍历执行它们的run方法
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
		    // 出现异常后,调用listeners.failed()、context.close()方法,并打印出异常信息
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

		try {
		    // 9.遍历执行SpringApplicationRunListener的running()方法
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

基本流程:
1.从spring.factories 读取 listener,进行预启动;
2.设置环境变量、banner信息、配置信息等;
3. 创建springApplication上下文;
4. 预初始化上下文;
5.调用refresh 加载ioc容器(加载所有的自动配置类、创建servlet容器); -》底层是Spring框架来实现的
6.监听器启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值