Springboot源码解析:SpringApplication#run(2)

本文详细解析了Spring Boot项目的启动流程,从ApplicationArguments的封装,ConfigurableEnvironment的准备,到ApplicationContext的创建,以及Banner的打印和FailureAnalyzers的初始化,深入理解Spring Boot如何一步步启动并运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

	private final Source source;
	private final String[] args;

	public DefaultApplicationArguments(String[] args) {
		Assert.notNull(args, "Args must not be null");
		this.source = new Source(args);
		this.args = args;
	}
	
	private static class Source extends SimpleCommandLinePropertySource {

		Source(String[] args) {
			super(args);
		}

		@Override
		public List<String> getNonOptionArgs() {
			return super.getNonOptionArgs();
		}

		@Override
		public List<String> getOptionValues(String name) {
			return super.getOptionValues(name);
		}
	}

意思就是将 main方法的参数封装起来。

二、ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

需要提前说明的是,listeners就是我们前面获取的整个run方法的监听器SpringApplicationRunListeners,applicationArguments则封装了main方法的参数,那就看一下这个方法的实现吧:

	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		//1、创建ConfigurableEnvironment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		//2、配置ConfigurableEnvironment
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		//3、发布事件
		listeners.environmentPrepared(environment);
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}

上面代码一共标注了该方法执行所经历的三个过程:
1、创建ConfigurableEnvironment

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		if (this.webEnvironment) {
			return new StandardServletEnvironment();
		}
		return new StandardEnvironment();
	}

因为该项目是一个web项目,所以执行new StandardServletEnvironment(),StandardServletEnvironment这个类的继承实现体系如下:
在这里插入图片描述

  • PropertyResolver:解析属性的规范
  • Environment:当前正在运行的应用环境的规范
  • ConfigurablePropertyResolver:用户可定制化PropertyResolver在解析和转换property时候的逻辑
  • ConfigurableEnvironment:大多数应用环境都要实现此接口,可以设置配置文件等
  • ConfigurableWebEnvironment:在ConfigurableEnvironment的基础上,可以初始化与servlet相关的属性资源
  • AbstractEnvironment:实现了ConfigurableEnvironment接口,默认属性和存储容器的定义,并且实现了ConfigurableEnvironment种的方法,并且为子类预留可覆盖了扩展方法
  • StandardEnvironment:继承自AbstractEnvironment,非Servlet(Web)环境下的标准Environment实现
  • StandardServletEnvironment:继承自StandardEnvironment,Servlet(Web)环境下的标准Environment实现

创建StandardServletEnvironment对象的时候,会依次执行如下代码:

	private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);

	public AbstractEnvironment() {
		customizePropertySources(this.propertySources);
		if (logger.isDebugEnabled()) {
			logger.debug("Initialized " + getClass().getSimpleName() + " with PropertySources " + this.propertySources);
		}
	}

	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
		propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
		if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
			propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
		}
		super.customizePropertySources(propertySources);
	}
	
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

我们可以看到,一直在往propertySources中添加对象,propertySources是MutablePropertySources类型的,其中维护了一个集合:

public class MutablePropertySources implements PropertySources {

	private final Log logger;
	private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
	//将propertySource添加到最低的优先级
	public void addLast(PropertySource<?> propertySource) {
		if (logger.isDebugEnabled()) {
			logger.debug("Adding PropertySource '" + propertySource.getName() + "' with lowest search precedence");
		}
		removeIfPresent(propertySource);
		this.propertySourceList.add(propertySource);
	}
}

因为MutablePropertySources的adddLast方法是将参数以最低的优先级添加到CopyOnWriteArrayList中,所以我们可以预见的是,它们的执行顺序为:
new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME)----------》
new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME)-------》
new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME)-------------------------------》
new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())-------------》
new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment())

三、Banner printedBanner = printBanner(environment)

这个方法不用看,就是打印一个banner,不涉及任何应用逻辑。

四、context = createApplicationContext();

	private Class<? extends ConfigurableApplicationContext> applicationContextClass;
	public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
	protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				//因为该项目是web环境,所有接下来的工作就是加载org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
				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);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}

接下来加载org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext,该类的继承体系如下图:
在这里插入图片描述构造方法如下:

	public AnnotationConfigEmbeddedWebApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

1》初始化reader

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));
	}

	private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		//EnvironmentCapable是一个标识接口,表明该实例是否包含并且暴露一个org.springframework.core.env.Environment的引用,因为该接口实现了ApplicationContext接口,ApplicationContext接口又继承了EnvironmentCapable接口,所以下面的判断为true,其中getEnvironment方法的实现是放在AbstractApplicationContext中,最终会调用org.springframework.web.context.support.GenericWebApplicationContext#createEnvironment去创建一个StandardServletEnvironment
		if (registry instanceof EnvironmentCapable) {
			return ((EnvironmentCapable) registry).getEnvironment();
		}
		return new StandardEnvironment();
	}
	

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

2》初始化scanner
创建扫描器

五、new FailureAnalyzers(context);

	FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
		Assert.notNull(context, "Context must not be null");
		this.classLoader = (classLoader == null ? context.getClassLoader() : classLoader);
		this.analyzers = loadFailureAnalyzers(this.classLoader);
		prepareFailureAnalyzers(this.analyzers, context);
	}
	private void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
			ConfigurableApplicationContext context) {
		for (FailureAnalyzer analyzer : analyzers) {
			prepareAnalyzer(context, analyzer);
		}
	}
	private void prepareAnalyzer(ConfigurableApplicationContext context,
			FailureAnalyzer analyzer) {
		if (analyzer instanceof BeanFactoryAware) {
			((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值