//自定义应用上下文初始化器 在项目启动的时候 被加载
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("自定义应用程序上下文初始化器,根据自己的需求来写,这里只是一个简单的案例");
//获取配置环境
ConfigurableEnvironment configurableEnvironment=applicationContext.getEnvironment();
//获取属性来源
MutablePropertySources mutablePropertySources=configurableEnvironment.getPropertySources();
// 配置属性 属性源头 就是application.properties文件的内容
PropertySource<?> propertySource=mutablePropertySources.get("configurationProperties");
//application.properties里面对应的key名称
Object value= propertySource.getProperty("www.name");
System.out.println(value);
}
}
//我们可以在项目的resources目录下的META-INF文件夹创建spring.factories
#应用上下文初始化器 自己的初始化加载器类路径
org.springframework.context.ApplicationContextInitializer=\
com.example.demo2.config.MyApplicationContextInitializer
//当我们的项目启动之后,先进入这个方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
}
//然后我们点击进去这个方法
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 = getClassLoader();
// 然后我们去找loadFactoryNames这个方法 获取我们在所有jar包里面的spring.factories文件里面
org.springframework.context.ApplicationContextInitializer下面包含的所有信息
Set<String> names = new LinkedHashSet<(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//我们可以看下效果,拿到了所有jar包对应的ApplicationContextInitializer下面的类
names = {LinkedHashSet@3495} size = 7
0 = "com.example.demo2.config.MyApplicationContextInitializer"
1 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
2 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
3 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
4 = "org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer"
5 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
6 ="org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener"
// 创建spring工厂实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 排序 最后返回这个spring工厂实例
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//加载工厂名称
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
// 吧当前工厂类的名称 获取到就是 org.springframework.context.ApplicationContextInitializer
String factoryClassName = factoryClass.getName();
// 然后我们进入loadSpringFactories这个方法
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
//加载spring工厂
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//从map中拿 是否有这个存在 如果存在 直接返回
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//我们看下这个参数FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 意思就是我们要去读取所有jar包下面的这个文件,包括我们自己的文件
//我们自定义的 他会去找 E:\demo2\target\classes\META-INF这个目录
//其他的jar包 会去找maven仓库下的jar包的路径,例如下面的
file:/D:/自己的maven仓库/org/springframework/boot/spring-boot/2.1.7.RELEASE/spring-boot-2.1.7.RELEASE.jar!/META-INF/spring.factories
file:/D:/自己的maven仓/org/springframework/boot/spring-boot-autoconfigure/2.1.7.RELEASE/spring-boot-autoconfigure-2.1.7.RELEASE.jar!/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 factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
//最后返回
cache.put(classLoader, result);
return result;
}
}
//等上面的代码都初始化完毕之后 我们在进入这个方法
public ConfigurableApplicationContext run(String... args) {
// 进入这个方法 准备上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
}
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
// 然后再进入这个方法
applyInitializers(context);
}
//应用初始化器
protected void applyInitializers(ConfigurableApplicationContext context) {
// 循环所有的初始化类
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
//这个时候 如果我们自己的初始化类打一个断点,就会跳到对应的类中
initializer.initialize(context);
}
}
//因为我们自定义的初始化加载器实现了ApplicationContextInitializer所以
//当initializer.initialize执行的时候 就会进来我们的自定义初始化方法
public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("自定义应用程序上下文初始化器"); }
}