栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringApplication的构造方法源码分析一

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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> 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

// orgspringframeworkbootspring-boot2.2.4.RELEASEspring-boot-2.2.4.RELEASE.jar!META-INFspring.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
// orgspringframeworkbootspring-boot-autoconfigure2.2.4.RELEASEspring-boot-autoconfigure-2.2.4.RELEASE.jar!META-INFspring.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, java.lang.Class[], java.lang.Object...)
private  Collection getSpringFactoriesInstances(Class 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 names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 创建配置实例对象
		List 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 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> loadSpringFactories(@Nullable ClassLoader classLoader) {
		// 先看看缓存中有没有,有就返回,springboot第一次肯定没有,但是spring cloud当使用bootstrap启动时,bootstrap会创建SpringApplication子容器,加缓存可以提高效率
		MultiValueMap result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			// classLoader != null 
			// FACTORIES_RESOURCE_LOCATION = META-INF/spring.factories
			Enumeration 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> 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  List createSpringFactoriesInstances(Class type, Class[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set names) {
		// parameterTypes = new Class[] {} 
		// args 为空
		List 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
// orgspringframeworkbootspring-boot2.2.4.RELEASEspring-boot-2.2.4.RELEASE.jar!META-INFspring.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
// orgspringframeworkbootspring-boot-autoconfigure2.2.4.RELEASEspring-boot-autoconfigure-2.2.4.RELEASE.jar!META-INFspring.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方法所在的启动类
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1006502.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号