SpringBoot(2.0.3)启动源码分析

SpringBoot启动分析

  SpringBoot源码分析分为两部分:

  1. 加载所有starter类型得jar和配置文件
  2. 生成ApplicationContext,调用Spring中得refresh()方法

     SpringBoot的运行原理是基于Spring的,所以熟悉Spring源码的人更能快速的理解SpringBoot的源码,下面开始分析。
     SpringBoot的入口是SpringApplication中的run()方法,所以流程分为两部分:构造器部分和run()方法实际执行SpringIOC的部分。

  • SpringApplication构造器源码分析(一)

构造器源代码如下:

    /**
	 * 1.构造器主要是把确定当前应用的类型,比如当前应用是Servlet/REACTIVE/NONE
	 * 2.扫描所有的META-INF/spring.factories文件,找到对应的类,填充到属性中,
	 * 	比如:在spring-boot-2.0.3.RELEASE.jar包中的META-INF/spring.factories文件中的ConfigFileApplicationListener类,
	 * 		在onApplicationEvent()类中加载的用户配置文件
	 * @param resourceLoader
	 * @param primarySources
	 */
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//根据当前项目中包的配置找到当前项目环境:比如是SERVLET或者是REACTIVE或者就是一个jar
		this.webApplicationType = deduceWebApplicationType();
		//找到当前所有META-INF/spring.factories文件下(包括jar)下的所有实现了ApplicationContextInitializer接口的类,set到initializers属性中
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		//找到当前所有META-INF/spring.factories文件下(包括jar)下的所有实现了ApplicationListener接口的类,set到listeners属性中
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
  • SpringApplication#run()方法分析(二)

      public ConfigurableApplicationContext run(String... args) {
     	//计时器
     	StopWatch stopWatch = new StopWatch();
     	stopWatch.start();
     	ConfigurableApplicationContext context = null;
     	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
     	configureHeadlessProperty();
     	//生成一个SpringApplication的监听器,专门监听启动过程
     	SpringApplicationRunListeners listeners = getRunListeners(args);
     	//启动器开始
     	listeners.starting();
     	try {
     		//启动参数封装
     		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
     				args);
     		//创建一个Enviroment,处理激活文件
     		ConfigurableEnvironment environment = prepareEnvironment(listeners,
     				applicationArguments);
     		configureIgnoreBeanInfo(environment);
     		//打印banner
     		Banner printedBanner = printBanner(environment);
     		//根据环境类型创建一个ApplicationContext,如果是Servlet的话,创建的是AnnotationConfigServletWebServerApplicationContext类
     		context = createApplicationContext();
     		exceptionReporters = getSpringFactoriesInstances(
     				SpringBootExceptionReporter.class,
     				new Class[] { ConfigurableApplicationContext.class }, context);
     		/**
     		 * 1. 调用ApplicationContextInitializer类的initialize()
     		 * 2. 调用所有的ApplicationListener的onApplicationEvent()方法,此处为观察者模式,上文说的加载自己的配置文件就是在这里加载的,对应的 类为ConfigFileApplicationListener类
     		 */
     		prepareContext(context, environment, listeners, applicationArguments,
     				printedBanner);
     		/**
     		 * 1.调用AbstractApplicationContext中的refresh方法,此处为即为SpringBoot的核心,也是Spring的核心,Spring的上下文都会调用到这里,
     		 * 2.在调用refresh方法的时候,会有一个onRefresh方法,调用到AnnotationConfigServletWebServerApplicationContext类的父类ServletWebServerApplicationContext中的onRefresh()方法,这里回根据
     		 * 	  配置去加载对应的服务器。
     		 */
     		refreshContext(context);
     		afterRefresh(context, applicationArguments);
     		stopWatch.stop();
     		if (this.logStartupInfo) {
     			new StartupInfoLogger(this.mainApplicationClass)
     					.logStarted(getApplicationLog(), stopWatch);
     		}
     		listeners.started(context);
     		/**
     		 * 调用ApplicationRunner/CommandLineRunner的实现类,项目启动就会访问,在这里做一个项目启动的扩展。
     		 */
     		callRunners(context, applicationArguments);
     	}
     	catch (Throwable ex) {
     		handleRunFailure(context, ex, exceptionReporters, listeners);
     		throw new IllegalStateException(ex);
     	}
     	try {
     		listeners.running(context);
     	}
     	catch (Throwable ex) {
     		handleRunFailure(context, ex, exceptionReporters, null);
     		throw new IllegalStateException(ex);
     	}
     	return context;
     }
    

到此,SpringBoot的整个流程就结束了,但是还有很多东西没有写,比如@Configuration是怎么解析的,其实就跟Spring的流程有关系了,就会在ConfigurationClassPostProcessor类中解析,实现了BeanDefinitionRegistryPostProcessor接口,会在refresh()方法中执行,postProcessBeanDefinitionRegistry()方法…这些都是Spring的东西。至于SpringBoot,总结代码如下
在这里插入图片描述
以上就是对SpringBoot2.0.3源码的大致流程分析。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值