Spring Boot 2.x 启动全过程源码分析

Spring Boot 2.x 启动全过程源码分析


SpringApplication 实例 run 方法运行过程

/**
	 * Run the Spring application, creating and refreshing a new 运行Spring应用程序,创建并刷新新的
	 * {@link ApplicationContext}. 应用上下文
	 * @param args the application arguments 应用程序参数(usually passed from a Java main method通常从java主方法传递) 
	 * @return a running {@link ApplicationContext} 返回一个正在运行的应用上下文
	 */
	public ConfigurableApplicationContext run(String... args) {
	    //1.创建并启动计时监控类
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		// 2、初始化应用上下文
		ConfigurableApplicationContext context = null;
		//3.启动故障分析器
		FailureAnalyzers analyzers = null;
		//4.设置系统属性【java.awt.headless】,为true则启用headless模式支持
		configureHeadlessProperty();
		  //5.通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,
          //找到声明的所有SpringApplicationRunListener的实现类并将其实例化,
        //之后逐个调用其started()方法,广播SpringBoot要开始执行了。
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
		    //6.初始化默认应用参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			 //7.创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile),
            //并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法,广播Environment准备完毕。
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			//8.创建 Banner 打印类
			Banner printedBanner = printBanner(environment);
			//9.根据webEnvironment的值来决定创建何种类型的ApplicationContext对象
            //如果是web环境,则创建org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
            //否则创建org.springframework.context.annotation.AnnotationConfigApplicationContext
			context = createApplicationContext();
			//10.注册启动故障分析器
			analyzers = new FailureAnalyzers(context);
			//11.为ApplicationContext加载environment,之后逐个执行ApplicationContextInitializer的initialize()方法
			//来进一步封装ApplicationContext,
            //并调用所有的SpringApplicationRunListener的contextPrepared()方法,
            //EventPublishingRunListener只提供了一个空的contextPrepared()方 法,之后初始化IoC容器,
            //并调用SpringApplicationRunListener的contextLoaded()方法,广播ApplicationContext的IoC加载完成,
            //12.这里就包括通过**@EnableAutoConfiguration**导入的各种自动配置类。
            //将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			//13.初始化所有自动配置类,调用ApplicationContext的refresh()方法
			refreshContext(context);
			//14.遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法。
            //该过程可以理解为是SpringBoot完成ApplicationContext初始化前的最后一步工作,
            //我们可以实现自己的ApplicationRunner或者CommandLineRunner,来对SpringBoot的启动过程进行扩展。           
			afterRefresh(context, applicationArguments);
			//15.调用所有的SpringApplicationRunListener的finished()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程。
			listeners.finished(context, null);
			//16.关闭任务执行时间监听器
			stopWatch.stop();
			//17.如果开启日志,则打印执行是时间
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
		  //调用异常分析器打印报告,调用所有的SpringApplicationRunListener的finished()方法将异常信息发布出去
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
  1. 创建并启动计时监控类
	/**
	 * 构造一个新的stopwatch 不能启动任何任务
	 */
	public StopWatch() {
		this("");
	}
	 /**
	  * 启动未命名的任务
	 *在不调用此方法的情况下(调用top方法) 调用计时方法,则结果是不确定的
	 */
	public void start() throws IllegalStateException {
		start("");
	}

public void start(String taskName) throws IllegalStateException {
		if (this.running) {
			throw new IllegalStateException("Can't start StopWatch: it's already running");
		}
		//是否正在运行
		this.running = true;
		//当前任务的名称
		this.currentTaskName = taskName;
		//开始时间
		this.startTimeMillis = System.currentTimeMillis();
	}
  1. 设置系统属性 java.awt.headless 的值
	//设置jdk系统属性java.awt.headless,默认情况为true即开启;
	private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
				SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}
  1. 创建所有 Spring 运行监听器并发布应用启动事件
     //根据args获取所有SpringApplicationRunListeners监听器
     SpringApplicationRunListeners listeners = getRunListeners(args);
     // 触发启动事件,启动监听器会被调用,一共5个监听器被调用
    listeners.starting();

创建 Spring 运行监听器相关的源码:

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

//通过Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
//类型加载对应的监听器,并创建 SpringApplicationRunListener实例,
//看下’SpringApplicationRunListener’的构造方法

  // 接受一个Log和Collection对象并赋给类成员变量
  private final Log log;
    private final List<SpringApplicationRunListener> listeners;
        SpringApplicationRunListeners(Log log,
        		Collection<? extends SpringApplicationRunListener> listeners) {
        	this.log = log;
        	this.listeners = new ArrayList<SpringApplicationRunListener>(listeners);
        }

我们重点看getSpringFactoriesInstances:

	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<String>(
		       //这里用set来防止类被重复加载 loadFactoryNames(type, classLoader)来获取类的全限定名称,为后续进行实例化。
		       //这里获取的就是之前读 取spring.factories文件放到的cache中去拿,
		       //因为在spring.factories中根据类型SpringApplicationRunListener读取到的工厂类
		       //是EventPublishingRunListener(这是springboot统一处理事件的类)
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//这里创建事件处理的工厂实例
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
	String factoryClassName = factoryClass.getName();
	try {
     // 通过类加载器获取resources; "META-INF/spring.factories"; 代码会去扫描项目工程中/META-INF下的spring.factories文件,获取   org.springframework.boot.SpringApplicationRunListener对应数据 
		Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		List<String> result = new ArrayList<String>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
			String propertyValue = properties.getProperty(factoryClassName);
			for (String factoryName : StringUtils.commaDelimitedListToStringArray(propertyValue)) {
				result.add(factoryName.trim());
			}
		}
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

spring.factories

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

由此可知this.getRunListeners(args) 最终拿到的是EventPublishingRunListener

  1. 初始化默认应用参数类
       // 参数封装,也就是在命令行下启动应用带的参数,如--server.port=8081
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);

5.根据运行监听器和应用参数来准备 Spring 环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		//Create and configure the environment  创建和配置环境
	    //获取或创建环境
		ConfigurableEnvironment environment = getOrCreateEnvironment();
	 // 配置环境:配置PropertySources和activeProfiles
		configureEnvironment(environment, applicationArguments.getSourceArgs());
	   //listeners环境准备(就是广播ApplicationEnvironmentPreparedEvent事件
		listeners.environmentPrepared(environment);
	   //如果是非web环境,将环境转换成StandardEnvironment
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}

我们继续看下getOrCreateEnvironment:

// 获取或创建Environment,很显然我们这里是创建StandardServletEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
    // 存在则直接返回
    if (this.environment != null) {
        return this.environment;
    }
    // 根据webApplicationType创建对应的Environment
    // webApplicationType的值还记得在哪获取到的吗?不知道的请去看我的springboot源码一
    if (this.webApplicationType == WebApplicationType.SERVLET) {
        // 标准的Servlet环境,也就是我们说的web环境
        return new StandardServletEnvironment();    
    }
     // 标准环境,非web环境
    return new StandardEnvironment();               
}

getOrCreateEnvironment方法创建并返回了一个环境:StandardServletEnvironment
我们继续往下看configureEnvironment:

protected void configureEnvironment(ConfigurableEnvironment environment,
		String[] args) {
		//配置PropertySource 
	configurePropertySources(environment, args);
	//配置Profile
	configureProfiles(environment, args);
}

我们来看 configurePropertySources的源码如下:

		protected void configurePropertySources(ConfigurableEnvironment environment,
				String[] args) {
			MutablePropertySources sources = environment.getPropertySources();
				//首先查看SpringApplication对象的成员变量defaultProperties,
			//如果该变量非null且内容非空,则将其加入到Environment的PropertySource列表的最后
			if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
				sources.addLast(
						new MapPropertySource("defaultProperties", this.defaultProperties));
			}
			//然后查看SpringApplication对象的成员变量addCommandLineProperties和main函数的参数args,
			//如果设置了addCommandLineProperties=true,且args个数大于0,
			//那么就构造一个由main函数的参数组成的PropertySource放到Environment的PropertySource列表的最前面(这就能保证,
				我们通过main函数的参数来做的配置是最优先的,可以覆盖其他配置)。
				由于没有配置defaultProperties且main函数的参数args个数为0,所以这个函数什么也不做。
			if (this.addCommandLineProperties && args.length > 0) {
				String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
				if (sources.contains(name)) {
					PropertySource<?> source = sources.get(name);
					CompositePropertySource composite = new CompositePropertySource(name);
					composite.addPropertySource(new SimpleCommandLinePropertySource(
							name + "-" + args.hashCode(), args));
					composite.addPropertySource(source);
					sources.replace(name, composite);
				}
				else {
				    // 将其放到第一位置
					sources.addFirst(new SimpleCommandLinePropertySource(args));
				}
			}
		}

我们接下来看configureProfiles:

   //首先会读取Properties中key为spring.profiles.active的配置项,配置到Environment,
	//然后再将SpringApplication对象的成员变量additionalProfiles加入到Environment的active profiles配置中
    protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
        //保证environment的activeProfiles属性被初始化了。
    	environment.getActiveProfiles(); // ensure they are initialized
    	// 如果存在其他的Profiles,则将这些Profiles放到第一的位置。
    	// But these ones should go first (last wins in a property key clash)
    	Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
    	profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
    	environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
    }

接着来看 listeners.environmentPrepared(environment):

listeners.environmentPrepared(environment);
//广播ApplicationEnvironmentPreparedEvent事件
public void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

6.创建 Banner 打印类

Banner printedBanner = printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = (this.resourceLoader != null)
				? this.resourceLoader : new DefaultResourceLoader(getClassLoader());
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
				resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

7.创建应用上下文

context = createApplicationContext();

	// 根据SpringApplication的webEnvironment来实例化对应的上下文;如果webEnvironment的值是true,
	//那么实例化AnnotationConfigEmbeddedWebApplicationContext, 
	//如果是false则实例化 AnnotationConfigApplicationContext
	protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			contextClass = Class.forName(this.webEnvironment
					? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Unable create a default ApplicationContext, "
							+ "please specify an ApplicationContextClass",
					ex);
		}
	}
	//利用反射调用其中一个ApplicationContext的构造方法进行实例化
	return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

8.初始化了FailureAnalyzers

analyzers = new FailureAnalyzers(context);

	FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
	Assert.notNull(context, "Context must not be null");
	this.classLoader = (classLoader != null) ? classLoader : context.getClassLoader();
	//初始化在spring.factory文件中的名称为:“org.springframework.boot.diagnostics.FailureAnalyzer”的对象
	this.analyzers = loadFailureAnalyzers(this.classLoader);
	//这个方法就是触发初始化的FailureAnalyzer对象,如果是BeanFactoryAware类型的,
	//则调用其setBeanFactory方法,需要注意的是,此时的bean,还没有加载,
	//bean的加载过程还在后面,所以此时获取的beanFactory是没有bean属性的
	prepareFailureAnalyzers(this.analyzers, context);
}

9.准备应用上下文

/**
     * 准备应用上下文
     * @param context AnnotationConfigServletWebServerApplicationContext实例
     * @param environment SpringApplication中的StandardServletEnvironment实例
     * @param applicationArguments SpringApplication中的DefaultApplicationArguments实例
     * @param printedBanner 默认使用SpringApplicationBanner实例
     */
    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        //设置context(上下文)环境
        //统一ApplicationContext和Application,使用Application的environment
        context.setEnvironment(environment);
        //ApplicationContext的后置处理
        postProcessApplicationContext(context);
        //执行Initializers
        applyInitializers(context);
        //发布contextPrepared事件
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            //配置了info日志
            //打印启动和profile日志
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        //获取到DefaultListableBeanFactory实例
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //注册名为springApplicationArguments,值为applicationArguments的单例bean
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        //banner不为空,那么注册名为springBootBanner,值为printedBanner的单例bean
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            //allowBeanDefinitionOverriding默认为false
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 获取sources列表,获取到我们的YanggxApplication.class
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //初始化bean加载器,并加载bean到应用上下文
        load(context, sources.toArray(new Object[0]));
        //发布contextLoaded事件
        listeners.contextLoaded(context);
    }
}

10.刷新应用上下文

refreshContext(context);
private void refreshContext(ConfigurableApplicationContext context) {
		//这里面最重要的就是这个refresh方法,我们继续跟进
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}
	
protected void refresh(ApplicationContext applicationContext) {
       //继续进入refresh方法
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}
	
    	@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
    // 准备刷新
    prepareRefresh();

    // 通知子类刷新内部bean工厂
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // 准备bean工厂以便在此上下文中使用
    prepareBeanFactory(beanFactory);

    try {
    	// 允许上下文子类中对bean工厂进行后处理
    	postProcessBeanFactory(beanFactory);

    	// 在bean创建之前调用BeanFactoryPostProcessors后置处理方法
    	invokeBeanFactoryPostProcessors(beanFactory);

    	// 注册BeanPostProcessor
    	registerBeanPostProcessors(beanFactory);

    	// 注册DelegatingMessageSource
    	initMessageSource();

    	// 注册multicaster
    	initApplicationEventMulticaster();

    	// 创建内置的Servlet容器
    	onRefresh();

    	// 注册Listener
    	registerListeners();

    	// 完成BeanFactory初始化,初始化剩余单例bean
    	finishBeanFactoryInitialization(beanFactory);

    	// 发布对应事件
    	finishRefresh();
    }

    catch (BeansException ex) {
    	if (logger.isWarnEnabled()) {
    		logger.warn("Exception encountered during context initialization - " +
    					"cancelling refresh attempt: " + ex);
    	}

    	// Destroy already created singletons to avoid dangling resources.
    	destroyBeans();

    	// Reset 'active' flag.
    	cancelRefresh(ex);

    	// Propagate exception to caller.
    	throw ex;
    }

    finally {
    	// Reset common introspection caches in Spring's core, since we
    	// might not ever need metadata for singleton beans anymore...
    	resetCommonCaches();
    }
    }
}
此方法由于内容比较多,下次重开一篇博客专门跟进!

11.应用上下文刷新后置处理

afterRefresh(context, applicationArguments);
//在刷新上下文后调用
protected void afterRefresh(ConfigurableApplicationContext context,
		ApplicationArguments args) {
	callRunners(context, args);
}
//如果实现了ApplicationRunner或CommandLineRunner就去调用实现的方法
private void callRunners(ApplicationContext context, ApplicationArguments args) {
	List<Object> runners = new ArrayList<Object>();
	runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
	runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
	AnnotationAwareOrderComparator.sort(runners);
	for (Object runner : new LinkedHashSet<Object>(runners)) {
		if (runner instanceof ApplicationRunner) {
			callRunner((ApplicationRunner) runner, args);
		}
		if (runner instanceof CommandLineRunner) {
			callRunner((CommandLineRunner) runner, args);
		}
	}
}

12.调用所有的SpringApplicationRunListener的finished()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程。

private void callFinishedListener(SpringApplicationRunListener listener,
		ConfigurableApplicationContext context, Throwable exception) {
	try {
		listener.finished(context, exception);
	}
	catch (Throwable ex) {
		if (exception == null) {
			ReflectionUtils.rethrowRuntimeException(ex);
		}
		if (this.log.isDebugEnabled()) {
			this.log.error("Error handling failed", ex);
		}
		else {
			String message = ex.getMessage();
			message = (message != null) ? message : "no error message";
			this.log.warn("Error handling failed (" + message + ")");
		}
	}
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
	SpringApplicationEvent event = getFinishedEvent(context, exception);
	if (context != null && context.isActive()) {
		// Listeners have been registered to the application context so we should
		// use it at this point if we can
		context.publishEvent(event);
	}
	else {
		// An inactive context may not have a multicaster so we use our multicaster to
		// call all of the context's listeners instead
		if (context instanceof AbstractApplicationContext) {
			for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
					.getApplicationListeners()) {
				this.initialMulticaster.addApplicationListener(listener);
			}
		}
		if (event instanceof ApplicationFailedEvent) {
			this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
		}
		this.initialMulticaster.multicastEvent(event);
	}
}

13.停止计时监控类

stopWatch.stop();

public void stop() throws IllegalStateException {
    //没有启动抛出异常
	if (!this.running) {
		throw new IllegalStateException("Can't stop StopWatch: it's not running");
	}
	//启动完成时间
	long lastTime = System.currentTimeMillis() - this.startTimeMillis;
	//启动总时间
	this.totalTimeMillis += lastTime;
	//内部类,用于保存有关在秒表中执行的一个任务的数据
	this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
	if (this.keepTaskList) {
		this.taskList.add(lastTaskInfo);
	}
	//返回定时任务的数量
	++this.taskCount;
	//启动标识设false
	this.running = false;
	//置空当前线程名称
	this.currentTaskName = null;
}

计时监听器停止,并统计一些任务执行信息。
14.输出日志记录执行主类名、时间信息

if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值