SpringApplication的构造方法源码分析一

SpringApplication的构造方法源码分析:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		// 传入的资源加载器为null,在执行run方法中对其赋值默认值
		// org.springframework.boot.SpringApplication#run(java.lang.String...)
		// Banner printedBanner = printBanner(environment);
		// ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader : new DefaultResourceLoader(getClassLoader());
		// org.springframework.util.ClassUtils#getDefaultClassLoader
		// Thread.currentThread().getContextClassLoader()
		this.resourceLoader = resourceLoader;
		// 主类不能为空(传入空数组new Class<?>[0]可以跳过此验证)
		Assert.notNull(primarySources, "PrimarySources must not be null");
		// 可以有多个主类进入,但是只有当前启动的main方法的类是后面的mainApplication,其他的做为资源类加入BeanFactory中管理
		// 	private Set<Class<?>> primarySources;
		// 关联参考:org.springframework.boot.SpringApplication#getAllSources
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 通过反射加载相关应用类,来推断web应用的类型
		// WebApplicationType.REACTIVE
		// WebApplicationType.NONE
		// WebApplicationType.SERVLET 当前项目默认启动就是servlet
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 自动装配:加载配置于/META-INF/spring.factories中key为org.springframework.context.ApplicationContextInitializer的所有初始化器
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		// 同上操作,加载监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 通过栈推断main方法所在的启动类,在spring cloud 中的bootstrap启动中会利用此主类
		// 参考org.springframework.cloud.bootstrap.BootstrapApplicationListener#bootstrapServiceContext
		// StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
		this.mainApplicationClass = deduceMainApplicationClass();
	}
1.自动装配 setInitializers

在这里插入图片描述

// \org\springframework\boot\spring-boot\2.2.4.RELEASE\spring-boot-2.2.4.RELEASE.jar!\META-INF\spring.factories
# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
// \org\springframework\boot\spring-boot-autoconfigure\2.2.4.RELEASE\spring-boot-autoconfigure-2.2.4.RELEASE.jar!\META-INF\spring.factories
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

源码分析setInitializers:

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

a.获取所有的初始化器实例对象:

// org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		// parameterTypes = new Class<?>[] {} 为空
		// args 为空
		// 获取classLoader
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		// 根据传入的类和classLoader加载META-INF/spring.factories中的配置
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 创建配置实例对象
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		// 排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

b.获取META-INF/spring.factories文件指定key的配置:

// org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		String factoryTypeName = factoryType.getName();
		// 从所有配置中获取指定的配置
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}

c.加载META-INF/spring.factories文件的所有配置:

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		// 先看看缓存中有没有,有就返回,springboot第一次肯定没有,但是spring cloud当使用bootstrap启动时,bootstrap会创建SpringApplication子容器,加缓存可以提高效率
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			// classLoader != null 
			// FACTORIES_RESOURCE_LOCATION = META-INF/spring.factories
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			// 以类加载器为key,将加载的自动装配的配置文件放入map缓存中
			// private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

d.反射加载实例对象:

// org.springframework.boot.SpringApplication#createSpringFactoriesInstances
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		// parameterTypes = new Class<?>[] {} 
		// args 为空
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				// 反射加载初始化器的类信息
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				// 验证父类的实例是否可以从子类得到分配
				// superType.isAssignableFrom(subType)
				Assert.isAssignable(type, instanceClass);
				// 反射获取构造器
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				// 反射创建实例java.lang.reflect.Constructor#newInstance
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}
2.自动装配 setListeners

观察者模式:org.springframework.context.ApplicationListener

// \org\springframework\boot\spring-boot\2.2.4.RELEASE\spring-boot-2.2.4.RELEASE.jar!\META-INF\spring.factories
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
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
// \org\springframework\boot\spring-boot-autoconfigure\2.2.4.RELEASE\spring-boot-autoconfigure-2.2.4.RELEASE.jar!\META-INF\spring.factories
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

源码和初始化器一致

3.deduceMainApplicationClass()
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;
	}
SpringApplication的构造方法总结
  1. 赋值加载器,加载器为null,后续使用默认加载器
  2. 验证主配置类不能为空
  3. 推断当前项目的web类型
  4. 自动装配初始化器
  5. 自动装配监听器
  6. 通过栈推断main方法所在的启动类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值