1.2、获取、创建 ApplicationContextInitializer

源码:
initialize
// **************** org.springframework.boot.SpringApplication ******************/
private List<ApplicationContextInitializer<?>> initializers;

private void initialize(Object[] sources) {
	//略...
	setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
	//略...
}
private List<ApplicationContextInitializer<?>> initializers;
public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
	this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
	this.initializers.addAll(initializers);
}

(1)创建所有 classpath 下所有 “Initializer”对象


源码:
initialize
 |- getSpringFactoriesInstances

// **************** org.springframework.boot.SpringApplication ******************/
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
	return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<? extends 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<String>(
			SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
			classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

(1.1)获取 classpath 下所有 “Initializer” 的全类名

源码:
initialize
 |- getSpringFactoriesInstances
     |- SpringFactoriesLoader.loadFactoryNames

SpringFactoriesLoader.loadFactoryNames() 方法在classpath下遍历 “META-INF/spring.factories” 文件,最终将这个文件中所有factoryClass指定类型的全类名解析出来,放入ArrayList中作为返回值

// **************** org.springframework.core.io.support.SpringFactoriesLoader ******************/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
	String factoryClassName = factoryClass.getName();
	try {
		Enumeration<URL> urls 
			= (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		List<String> result = new ArrayList<String>();
		while (urls.hasMoreElements()) {
			//本例中,其中一个spring.factories为:
			//jar:file:/D:/../org/springframework/boot/spring-boot/1.5.9.RELEASE/
			//spring-boot-1.5.9.RELEASE.jar!/META-INF/spring.factories
			URL url = urls.nextElement();
			// 将文件解析为Properties 类型
			Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
			// 从Properties文件中获取key为 factoryClassName 的值
			String factoryClassNames = properties.getProperty(factoryClassName);
			// 逗号分隔的字符串解析为String[],然后转为List放入result
			result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
		}
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
				"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

返回结果:
names = {LinkedHashSet@1647}  size = 6
 0 = "o.s.b.context.ConfigurationWarningsApplicationContextInitializer"
 1 = "o.s.b.context.ContextIdApplicationContextInitializer"
 2 = "o.s.b.context.config.DelegatingApplicationContextInitializer"
 3 = "o.s.b.context.embedded.ServerPortInfoApplicationContextInitializer"
 4 = "o.s.b.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
 5 = "o.s.b.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"

🤔​ Spring Boot 为什么把这些类配置在classpath下的 “META-INF/spring.factories” 文件中?

其实这是个扩展机制,用户自己可以开发一些第三方应用,在应用中创建 “META-INF/spring.factories” 文件,并在里面设置一些 Initializer ,用户在 Initializer 里实现自己的逻辑,这样在Spring Boot启动时就可以执行这些逻辑了。

(1.2)创建所有 “Initializer”实例

前面已经获取了classpath下所有的 Initializer 了,现在将其作为参数,调用 createSpringFactoriesInstances(...) 方法来创建这些 Initializer 的对象,并将创建好的对象放入 SpringApplication 中。


源码:
initialize
 |- getSpringFactoriesInstances
     |- createSpringFactoriesInstances

// **************** org.springframework.boot.SpringApplication ******************/
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
		Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
		Set<String> names) {
	List<T> instances = new ArrayList<T>(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;
}

(2)设置 SpringApplication 的“Initializer”


源码:
initialize
 |- setInitializers

// **************** org.springframework.boot.SpringApplication ******************/
private List<ApplicationContextInitializer<?>> initializers;
public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
	this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
	this.initializers.addAll(initializers);
}

1.2-Q1 什么是 ApplicationContextInitializer ?什么场景下使用?

1.2-Q2 设置这个initializers做什么用?

 0 = "o.s.b.context.ConfigurationWarningsApplicationContextInitializer"
 1 = "o.s.b.context.ContextIdApplicationContextInitializer"
 2 = "o.s.b.context.config.DelegatingApplicationContextInitializer"
 3 = "o.s.b.context.embedded.ServerPortInfoApplicationContextInitializer"
 4 = "o.s.b.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
 5 = "o.s.b.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"

1、搜索这个几个类,查看 initialize方法做了哪些事情?
2、选一个类,在其 initialize 第一行打上断点,debug程序,看看方法时候调用的?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java硕哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值