通过源码了解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

posted on 2020-01-08 16:41  四海骄阳  阅读(446)  评论(0编辑  收藏  举报

导航