springboot源码setInitializers分析

//自定义应用上下文初始化器 在项目启动的时候 被加载 
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("自定义应用程序上下文初始化器");
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Spring Boot源码分析,我可以提供一些基本的指导。 Spring Boot是一个用于简化Spring应用程序的框架。它提供了一种基于约定的配置方式,使得开发人员能够快速启动和部署应用程序。如果你想要深入了解Spring Boot源码,可以按照以下步骤进行: 1. 下载源码:你可以从Spring官方网站或者GitHub上获取Spring Boot源码。确保下载与你使用的版本相对应的源码。 2. 导入项目:使用你喜欢的集成开发环境(IDE)导入源码项目。Spring Boot使用Maven构建工具,所以确保你已经安装了Maven。 3. 了解核心模块:Spring Boot源码结构由许多模块组成。开始时,可以关注核心模块,如spring-bootspring-boot-autoconfigure和spring-boot-starter等。这些模块包含了Spring Boot框架的核心功能。 4. 阅读文档:Spring Boot为每个模块提供了详细的文档,包括类、方法和配置选项的说明。阅读文档将帮助你理解源码中的各个部分。 5. 调试和跟踪代码:使用IDE的调试功能,通过设置断点和跟踪代码的执行路径,来深入了解Spring Boot的工作原理。 6. 参考示例代码:Spring Boot源码中包含了许多示例代码,用于演示各种功能和用法。阅读这些示例代码可以帮助你更好地理解源码的实现方式。 请注意,Spring Boot源码非常庞大且复杂,需要一定的时间和经验来深入研究。建议先从核心模块开始,并结合阅读文档和调试代码的方式来进行学习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值