美文网首页spring学习
Spring-Boot--application-propert

Spring-Boot--application-propert

作者: Mr_1214 | 来源:发表于2018-05-19 19:48 被阅读79次
    spring boot默认已经配置了很多环境变量,例如,tomcat的默认端口是8080,项目的contextpath是“/”等等,spring boot允许你自定义一个application.properties文件,然后放在以下的地方,来重写spring boot的环境变量

    spring对配置application.properties的加载过程:

    1. 服务启动调用:SpringApplication.run
    2. 创建默认的环境参数:ConfigurableEnvironment
    3. 触发事件:ApplicationEnvironmentPreparedEvent
    4. 完成加载

    整个过程主要使用spring boot 内置的ConfigFileApplicationListener监听器监听ApplicationEnvironmentPreparedEvent事件完成对application.properties加载以及设置。


    下面我们来跟踪源码,看下spring boot是怎样完成对application.properties文件的加载

    • SpringApplication 入口 run:
    public ConfigurableApplicationContext run(String... args) {
            //无关的代码暂略
            .......
            ConfigurableApplicationContext context = null;
            FailureAnalyzers analyzers = null;
            configureHeadlessProperty();
            //获取执行监听器实例
            SpringApplicationRunListeners listeners = getRunListeners(args);
            ........
                //创建全局系统参数实例
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                        args);
                //创建    ConfigurableEnvironment 并触发ApplicationEnvironmentPreparedEvent事件    
                //加载配置的核心地方,spring启动首要做的事情
                ConfigurableEnvironment environment = prepareEnvironment(listeners,
                        applicationArguments);
          .........
        }
    

    prepareEnvironment方法

    private ConfigurableEnvironment prepareEnvironment(
                SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments) {
            // Create and configure the environment
            //创建一个配置环境信息,当是web环境时创建StandardServletEnvironment实例,非web环境时创建StandardEnvironment实例
            ConfigurableEnvironment environment = getOrCreateEnvironment();
            configureEnvironment(environment, applicationArguments.getSourceArgs());
            //核心事件触发方法,此方法执行后会执行所有监听ApplicationEnvironmentPreparedEvent事件的监听器,这里我们是跟踪application.properties文件的加载,就查看ConfigFileApplicationListener监听器都做了什么工作
            listeners.environmentPrepared(environment);
            if (!this.webEnvironment) {
                environment = new EnvironmentConverter(getClassLoader())
                        .convertToStandardEnvironmentIfNecessary(environment);
            }
            return environment;
        }
    
    • ConfigFileApplicationListener:
    public void onApplicationEvent(ApplicationEvent event) {
            //从此处可以看到当事件为ApplicationEnvironmentPreparedEvent时,执行onApplicationEnvironmentPreparedEvent方法
            if (event instanceof ApplicationEnvironmentPreparedEvent) {
                onApplicationEnvironmentPreparedEvent(
                        (ApplicationEnvironmentPreparedEvent) event);
            }
            if (event instanceof ApplicationPreparedEvent) {
                onApplicationPreparedEvent(event);
            }
        }
    

    onApplicationEnvironmentPreparedEvent

    private void onApplicationEnvironmentPreparedEvent(
                ApplicationEnvironmentPreparedEvent event) {
            //此处通过SpringFactoriesLoader加载EnvironmentPostProcessor所有扩展   
            List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
            //因为此监听器同样是EnvironmentPostProcessor的扩展实例,所以在此处将自己加入集合
            postProcessors.add(this);
            AnnotationAwareOrderComparator.sort(postProcessors);
            //遍历所有的EnvironmentPostProcessor扩展调用postProcessEnvironment
            //当然我们跟踪是application.properties所以主要查看当前实例的postProcessEnvironment方法
            for (EnvironmentPostProcessor postProcessor : postProcessors) {
                postProcessor.postProcessEnvironment(event.getEnvironment(),
                        event.getSpringApplication());
            }
        }
    

    postProcessEnvironment

    @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment,
                SpringApplication application) {
            //此处添加配置信息到environment实例中,此方法完成后就将application.properties加载到环境信息中
            addPropertySources(environment, application.getResourceLoader());
            configureIgnoreBeanInfo(environment);
            bindToSpringApplication(environment, application);
        }
    

    addPropertySources

    protected void addPropertySources(ConfigurableEnvironment environment,
                ResourceLoader resourceLoader) {
            //这里先添加一个Random名称的资源到环境信息中  
            RandomValuePropertySource.addToEnvironment(environment);
            //通过Loader加载application.properties并将信息存入环境信息中
            new Loader(environment, resourceLoader).load();
        }
    

    load

    public void load() {
    //创建一个资源加载器,spring boot默认支持PropertiesPropertySourceLoader,YamlPropertySourceLoader两种配置文件的加载
                this.propertiesLoader = new PropertySourcesLoader();
                this.activatedProfiles = false;
                //加载配置profile信息,默认为default
                ..........此处省略
                while (!this.profiles.isEmpty()) {
                    Profile profile = this.profiles.poll();
                    //遍历所有查询路径,默认路径有:classpath:/,classpath:/config/,file:./,file:./config/
                    for (String location : getSearchLocations()) {
                    //这里不仅仅是加载application.properties,当搜索路径不是以/结束,默认认为是文件名已存在的路径
                        if (!location.endsWith("/")) {
                            // location is a filename already, so don't search for more
                            // filenames
                            load(location, null, profile);
                        }
                        else {
                             //遍历要加载的文件名集合,默认为application
                            for (String name : getSearchNames()) {
                                load(location, name, profile);
                            }
                        }
                    }
                    this.processedProfiles.add(profile);
                }
    
                //将加载完成的配置信息全部保存到环境信息中共享
                addConfigurationProperties(this.propertiesLoader.getPropertySources());
            }
    

    load

    private void load(String location, String name, Profile profile) {
                //此处根据profile组装加载的文件名称以及资源所放置的组信息
                String group = "profile=" + (profile == null ? "" : profile);
                if (!StringUtils.hasText(name)) {
                    // Try to load directly from the location
                    loadIntoGroup(group, location, profile);
                }
                else {
                 
                        // Also try the profile-specific section (if any) of the normal file
                        loadIntoGroup(group, location + name + "." + ext, profile);
                    }
                }
            }
    

    loadIntoGroup

    private PropertySource<?> doLoadIntoGroup(String identifier, String location,
                    Profile profile) throws IOException {
                Resource resource = this.resourceLoader.getResource(location);
                PropertySource<?> propertySource = null;
                if (resource != null && resource.exists()) {
                    String name = "applicationConfig: [" + location + "]";
                    String group = "applicationConfig: [" + identifier + "]";
                    //资源加载核心方法,此处有两个实现,当后缀为,xml或者properties调用PropertiesPropertySourceLoader
                    //当后缀为yml或者yaml时,调用YamlPropertySourceLoader
                    
                    propertySource = this.propertiesLoader.load(resource, 
                }
            
                return propertySource;
            }
    
    • PropertiesPropertySourceLoader:
    @Override
        public PropertySource<?> load(String name, Resource resource, String profile)
                throws IOException {
            if (profile == null) {
                //此处调用PropertiesLoaderUtils工具类加载本地文件
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                if (!properties.isEmpty()) {
                    return new PropertiesPropertySource(name, properties);
                }
            }
            return null;
        }
    

    到此application.properties就真正的加载并共享到环境信息中,供系统其它地方调用。

    相关文章

      网友评论

        本文标题:Spring-Boot--application-propert

        本文链接:https://www.haomeiwen.com/subject/sqyydftx.html