zoukankan      html  css  js  c++  java
  • 通过源码了解springboot加载application.properties过程

    通过源码了解springboot加载application.properties过程
    原创天才小汪汪 发布于2018-09-27 16:52:31 阅读数 2494 收藏
    展开
    springboot有一个配置文件application.properties,我只知道有这么一个配置文件,但是springboot启动的时候,是在哪里加载该文件的,又如何找到该文件的?从源码去查看

    在main方法里执行该方法SpringApplication.run(Test.class, args);查看SpringApplication类的源码,进入run方法

    public static ConfigurableApplicationContext run(Object source, String... args) {
            return run(new Object[] { source }, args);
        }

    再进入 run(new Object[] { source }, args);方法

    public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
            return new SpringApplication(sources).run(args);
        }

    到这一步,可以看到创建一个新的SpringApplication,new SpringApplication(sources),并执行run()方法,先到构造方法去看一下,这类做了什么初始化的事

    public SpringApplication(Object... sources) {
            initialize(sources);
        }

    里面有一个initialize(sources);方法,再进去

    @SuppressWarnings({ "unchecked", "rawtypes" })
        private void initialize(Object[] sources) {
            if (sources != null && sources.length > 0) {
                this.sources.addAll(Arrays.asList(sources));
            }
            this.webEnvironment = deduceWebEnvironment();
            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }

    在上面的代码中, this.webEnvironment = deduceWebEnvironment();该方法主要是筛选sevlet和ConfigurableWebApplicationContext,如何有这两个就返回false,否则返回true,具体有什么作用,我也不知道,但跟这次讨论的问题无关,暂时放一边,setInitalizers()方法,看一下源码

    public void setInitializers(
                Collection<? extends ApplicationContextInitializer<?>> initializers) {
            this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
            this.initializers.addAll(initializers);
        }

    该方法就是将ApplicationContextInitializer的实现类加入 this.initializers集合中,在getSpringFactoriesInstances(
                    ApplicationContextInitializer.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;
        }

    在this.initializers中存放的就springboot所要加载的ApplicationContextInitializer实现类

    [org.springframework.boot.context.config.DelegatingApplicationContextInitializer,

    org.springframework.boot.context.ContextIdApplicationContextInitializer,

    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,

    org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer,

    org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,

    org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer]

    在这些实现类中,也没有涉及到application.properties文件的加载,暂时也不管,来看 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));方法,和上面加载ApplicationContextInitializer步骤一样,在this.listeners存储的ApplicationListener便有以下这些

    [org.springframework.boot.context.config.ConfigFileApplicationListener,

    org.springframework.boot.context.config.AnsiOutputApplicationListener,

    org.springframework.boot.logging.LoggingApplicationListener,

    org.springframework.boot.logging.ClasspathLoggingApplicationListener,

    org.springframework.boot.autoconfigure.BackgroundPreinitializer,

    org.springframework.boot.context.config.DelegatingApplicationListener,

    org.springframework.boot.builder.ParentContextCloserApplicationListener,

    org.springframework.boot.ClearCachesApplicationListener

    org.springframework.boot.context.FileEncodingApplicationListener,

    org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener]

    到这里便可以看到一个很重要的监听器ConfigFileApplicationListener

    public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
            ApplicationListener<ApplicationEvent>, Ordered {

        private static final String DEFAULT_PROPERTIES = "defaultProperties";

        // Note the order is from least to most specific (last one wins)
        private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";   //默认                                                                                                                                                                                 加载的位置

        private static final String DEFAULT_NAMES = "application";     //默认的配置文件名

        /**
         * The "active profiles" property name.
         */
        public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";

        /**
         * The "includes profiles" property name.
         */
        public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";

        /**
         * The "config name" property name.
         */
        public static final String CONFIG_NAME_PROPERTY = "spring.config.name";

        /**
         * The "config location" property name.
         */
        public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";

        /**
         * The default order for the processor.
         */
        public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;

        /**
         * Name of the application configuration {@link PropertySource}.
         */
        public static final String APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME = "applicationConfigurationProperties";

        private final DeferredLog logger = new DeferredLog();

        private String searchLocations;

        private String names;

        private int order = DEFAULT_ORDER;

        private final ConversionService conversionService = new DefaultConversionService();

        @Override
        public void onApplicationEvent(ApplicationEvent event) {
           .............................
        }
    ................

    }

    到这里终于找到了加载application.properties的类了,该类便是解析application.properties里配置的各个属性值,在prependProfile()方法解析.

    以上,SpringApplication只是将该类存在一个集合中,那么它又是在哪里开启这些监听呢

    到这里,进入run()方法去看一下

    public ConfigurableApplicationContext run(String... args) {
            //...........
            SpringApplicationRunListeners listeners = getRunListeners(args);
            listeners.starting();

          //...................

    }

    在这里,得到的是一个SpringApplicationRunListeners的实现类EventPublishingRunListener,并将其开启监听,EventPublishingRunListener里面如下做了如下处理

    public EventPublishingRunListener(SpringApplication application, String[] args) {
            this.application = application;
            this.args = args;
            this.initialMulticaster = new SimpleApplicationEventMulticaster();
            for (ApplicationListener<?> listener : application.getListeners()) {
                this.initialMulticaster.addApplicationListener(listener);
            }
        }

    在EventPublishingRunListener的构造函数里,application.getListeners()获取的就是SpringApplication中的this.listeners集合里存放的Listener.再来看listeners.starting();方法做了什么

    public void starting() {
            for (SpringApplicationRunListener listener : this.listeners) {
                listener.starting();
            }
        }

    它把集合里的所有listener都开启了监听.到此加载application.properties结束.

    总结:

    springboot通过SpringApplication类的构造函数,加载所需要的listener,在run()方法执行里,由EventPublishingRunListener开启所有的listener的监听.
    ————————————————
    版权声明:本文为CSDN博主「天才小汪汪」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_36009027/article/details/82868431

  • 相关阅读:
    k8s的chart学习(上)
    k8s的应用打包工具Helm
    k8s通过configmap管理应用配置信息
    k8s通过secret管理敏感信息
    k8s的持久化存储PV&&PVC
    k8s的存储Volume
    使用python获取整月每一天的系统监控数据生成报表
    NGUI的UISprite动态染色的一种方法
    VS生成后事件对文件的copy以及更换扩展名
    【转】搞清楚脚本中这些函数的调用规律
  • 原文地址:https://www.cnblogs.com/zhoading/p/12167462.html
Copyright © 2011-2022 走看看