SpringBoot启动流程简析(一)

最近在业务中碰到SpringBoot启动流程相关问题,故梳理记录下:

要点:本章主要梳理SpringBoot启动流程中是如何创建SpringApplication实例的。

启动主类代码如下:

@Slf4j
@SpringBootApplication
public class ItemFootprintApplication {
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(ItemFootprintApplication.class, args);
        log.info("spring boot 启动环境和配置信息如下:" + ctx.getEnvironment());
    }
}

首先进入到SpringApplication的run方法中看一下这个方法的内容:

/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified source using default settings.
	 * @param primarySource the primary source to load
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return the running {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Class<?> primarySource,
			String... args) {
		return run(new Class<?>[] { primarySource }, 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);
	}

(1) 创建SpringApplication对象;
(2) 调用SpringApplication的run方法,返回一个Spring上下文 ConfigurableApplicationContext的实例。

我们先去看看SpringApplication的构造函数的内容:

	public SpringApplication(Class<?>... primarySources) {
		this(null, 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));
		
		//(z1) 判断是否是web环境
		this.webApplicationType = deduceWebApplicationType();
		
		//(z2) 从spring.factories中获取ApplicationContextInitializer集合并赋值
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		
		//(z3) 从spring.factories中获取ApplicationListener集合并赋值		
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	
		this.mainApplicationClass = deduceMainApplicationClass();
	}

(z1) 判断是否是web环境

private WebApplicationType deduceWebApplicationType() {
		if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}
	
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

这里判断是不是web开发环境也很简单,就是看类路径下是能加载到javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext这两个两类,如果能加载到则是web环境,否则非web环境。

(z2) 从spring.factories中获取ApplicationContextInitializer集合

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<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<>(
		        //META-INF/spring.factories中加载ApplicationContextInitializer类型的类的全路径名
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//根据上一步获取到的类名,创建实例对象		
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		//排序		
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

(z3) 从spring.factories中获取ApplicationListener集合
与(z2) 类似

本章总结:
在启动SpringBoot的过程中,创建SpringApplication的实例的主要流程:
(1) deduceWebApplicationType()方法判断是不是web环境;
(2) 从spring.factories中加载org.springframework.context.ApplicationContextInitializer和org.springframework.context.ApplicationListener类型的对象并赋值到SpringApplication实例中;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值