Spring源码解读(十四)Boot启动类——SpringApplication.run

前言

Spring源码解读(十三)Boot启动类——SpringApplication构造方法 后,继续分析SpringApplication.run方法。

程序入口

启动方法中增加一些boot的新特性处理,但是对于spring核心部分依旧使用的AbstractApplicationContext.refresh方法。

	public ConfigurableApplicationContext run(String... args) {
		// 计时器记录启动耗时
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

		// 配置系统属性 java.awt.headless
		configureHeadlessProperty();

		// 创建spring运行监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 发布spring启动事件
		listeners.starting();
		try {
			// 应用的启动参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 加载环境配置
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 配置spring.beaninfo.ignore信息
			configureIgnoreBeanInfo(environment);
			// 打印启动banner
			Banner printedBanner = printBanner(environment);
			// 创建ConfigurableApplicationContext类型的应用上下文对象
			context = createApplicationContext();
			// 加载SpringBootExceptionReporter
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			// 将context进行封装,将上面得到的environment、listeners、applicationArguments、printedBanner都注册到context中
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// 刷新上下文对象,实际上调用的就是AbstractApplicationContext.refresh
			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;
	}

创建Spring运行监听器

	/**
	 * 创建Spring运行监听器,
	 * SpringApplicationRunListeners用来监听SpringApplication的run方法
	 * @param args
	 * @return
	 */
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

保存应用启动参数

使用DefaultApplicationAgrument对象记录启动时传入的args

	public DefaultApplicationArguments(String... args) {
		Assert.notNull(args, "Args must not be null");
		this.source = new Source(args);
		this.args = args;
	}

加载环境配置

	private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		// 创建ConfigurableEnvironment对象,根据web应用的类型返回不同的子类
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		// 对environment进行配置
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		// 为environment添加附加属性
		ConfigurationPropertySources.attach(environment);
		// 监听器发布环境参数加载事件
		listeners.environmentPrepared(environment);
		// 将环境参数绑定的spring应用中
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			// 对非自定义的环境进行转换
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		// 为environment添加附加属性
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

对environment进行配置

	protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
		if (this.addConversionService) {
			// 设置 conversionService
			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
			environment.setConversionService((ConfigurableConversionService) conversionService);
		}
		// 设置属性源
		configurePropertySources(environment, args);
		// 设置引用的配置文件
		configureProfiles(environment, args);
	}

设置属性源和引用配置文件

	protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		// 配置默认的属性源
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
		}
		// 添加来自启动参数的属性
		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("springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}


	protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
		Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(StringUtils.toStringArray(profiles));
	}

配置spring.beaninfo.ignore信息

	private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
		if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
			Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
			System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
		}
	}

创建ApplicationContext对象

根据不同的应用类型实例化不同的bean

	protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

加载SpringBootExceptionReporter

从META-INF/spring.factories文件中加载和实例化给定类型的工厂,在上篇 Spring源码解读(十三)Boot启动类——SpringApplication构造方法 已经分析过了。

对context进行封装

这一步是准备Context环境,主要分为6个步骤。

  • 统一ApplicationContext和Application使用environment
  • ApplicationContext后置处理
  • context初始化
  • 发布准备context事件
  • 为beanfactory添加必要的bean
  • 发布context加载成功事件
	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		// 为context设置env属性
		context.setEnvironment(environment);
		// ApplicationContext后置处理
		postProcessApplicationContext(context);
		// 初始化context
		applyInitializers(context);
		// 发布context准备完成事件
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// 为beanFactory添加系统必要的单例类
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// applicationArguments 启动参数
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			// 懒加载模式设置懒加载bean后置处理器
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 为context加载必要的配置,如beanName生成策略,env等
		load(context, sources.toArray(new Object[0]));
		// 发布context加载成功事件
		listeners.contextLoaded(context);
	}

为context设置环境参数

ConfigurableApplicationContext的几个实现类中对setEnvironment的处理都是一样的。最终都通过执行到了父类ClassPathScanningCandidateComponentProvider和AnnotatedBeanDefinitionReader的setEnvironment,在 Spring源码解读(十二)通过包路径扫描Bean——ClassPathBeanDefinitionScanner 已经分析过了。

	@Override
	public void setEnvironment(ConfigurableEnvironment environment) {
		super.setEnvironment(environment);
		this.reader.setEnvironment(environment);
		this.scanner.setEnvironment(environment);
	}

ApplicationContext后置处理

	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			// 想beanFactory注册beanName生成器,并指定生成器的beanName
			// CONFIGURATION_BEAN_NAME_GENERATOR = "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
			context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			if (context instanceof GenericApplicationContext) {
				// 对GenericApplicationContext的上下文环境设置 资源加载器
				((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
				// 对DefaultResourceLoader的上下文环境设置 ClassLoader
				((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
		if (this.addConversionService) {
			// 设置类型转换service
			context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
		}
	}

执行spring初始化器

执行org.springframework.context.ApplicationContextInitializer的子类的逻辑,这里涉及到很多个实现类,先不展开。

	protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
					ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			initializer.initialize(context);
		}
	}

为context加载必要的配置

	protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
			// 设置beanName生成器
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			// 设置资源加载器
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
			// 设置环境参数
			loader.setEnvironment(this.environment);
		}
		loader.load();
	}

刷新Context

执行的就是AbstractApplicationContext的refresh方法,具体分析在 Spring源码解读(一)启动流程分析——AbstractApplicationContext

	private void refreshContext(ConfigurableApplicationContext context) {
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
		refresh(context);
	}

	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}

刷新Context后的处理

这是一个空方法,留给子类扩展

	protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}

通知ApplicationRunner和CommandLineRunner

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值