【Spring boot读书笔记】 SpringApplication-初始化阶段(1)

一、概述

SpringApplication初始化阶段属于运行前的准备阶段,大多数Spring Boot应用直接或间接的使用SpringApplication API驱动Spring应用,SpringApplication允许指定应用的类型,大体上包括Web应用和非Web应用。从Spring Boot 2.0开始,Web应用又可以分为Servlet Web,Reactive Web。
当然Spring Application也可以调整Banner输出、配置默认属性的内容等。这些状态的变更操作只要在run()方法之前指定即可。简单来说,SpringApplication的准备阶段主要有两阶段完成:

  • 构造阶段
  • 配置阶段

二、SpringApplication 构造阶段

(1) 构造过程

在这里插入图片描述

(2) 源码解析

以最简单应用代码为例:

@SpringBootApplication
public class SimpleApplication {
	// 1.引导类 SimpleApplication.main()
    public static void main(String[] args) {
		// 2.执行SpringApplication.run()
        SpringApplication.run(SimpleApplication.class, args);
    }
}


public class SpringApplication {

	// 3.构建SpringApplication
	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}
	
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 4.推断Web应用类型
		this.webApplicationType = deduceWebApplicationType();
		// 5.加载Spring应用上下文初始化器(ApplicationContextInitialzer)
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		// 6.加载Spring应用事件监听器(ApplicationListener)
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 7.推断应用引导类
		this.mainApplicationClass = deduceMainApplicationClass();
	}
}

(3) 推断web应用类型

web应用类型判断依据:

  • DispatcherHandler
  • DispatcherServlet
  • Servlet
  • ConfigurableWebApplicationContext

(3.1) 当DispatcherHandler存在,且DispatcherServlet 不存在时,换言之SpringBoot仅仅依赖WebFlux存在时,此时的web应用类型为Reactive Web, 即WebApplicationType.REACTIVE
(3.2) 当Servlet和ConfigurableWebApplicationContext均不存在时,当前应用为非Web应用,WebApplicationType.NONE
(3.3) 当Spring WebFlux 和Spring Web MVC同时存在时,Web应用类型同样是Servlet,即WebApplicationType.SERVLET

源码实现:



	private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };
	
	private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.reactive.DispatcherHandler";

	private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.servlet.DispatcherServlet";
			+ 
	private WebApplicationType deduceWebApplicationType() {
		if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}
(4)加载Spring应用上下文初始化器 - ApplicationContextInitializer

Spring应用上行文的初始化器,主要通过Spring工厂加载机制来加载,即调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)),将返回META-INF/spring.factories资源配置的ApplicationContextInitializer实现名单,例org.spring.framework.boot:spring-boot:2.0.2.RELEASE中的内容:

#Application Context Initializers
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
org.springframework.boot.context.ContextIdApplicationContextInitializer,
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		...
		// 1.加载Spring应用上下文初始化器
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		...
	}
	
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}
	
	// 2.通过Spring工厂加载机制 查找ApplicationContextInitializer实现
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
	
	// 3. 构建ApplicationContextInitializer对象实例
	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

(5)加载Spring应用事件监听器 - ApplicationListener

Spring应用事件监听器加载过程与(4)中应用初始化器的加载过程类似,也是通过spring工厂加载机制加载META-INF/spring.factories文件中配置的ApplicationListener:

#Application Listeners
org.springframework.context.ApplicationListener=
org.springframework.boot.ClearCachesApplicationListener,
org.springframework.boot.builder.ParentContextCloserApplicationListener,
org.springframework.boot.context.FileEncodingApplicationListener,
org.springframework.boot.context.config.AnsiOutputApplicationListener,
org.springframework.boot.context.config.ConfigFileApplicationListener,
org.springframework.boot.context.config.DelegatingApplicationListener,
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.context.logging.LoggingApplicationListener,
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

源码解析:

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		...
		// 1.加载Spring应用事件监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		...
	}

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

	// 2.通过Spring工厂加载机制 查找ApplicationListener实现
	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<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

	// 3. 构建ApplicationListener对象实例
	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}
(6)推断应用引导类

推断应用引导类是SpringApplication构造过程的末尾动作:

	// 根据当前线程栈来判断其栈中哪个类包含main方法
	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值