SpringBoot加载配置源码

从启动类打断点进去:

public class Application{

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

进入 SpringApplication.run(Application.class, args):

    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }

 进入:run(new Class[]{primarySource}, args):

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

进入run(args):


    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 从这里跟进去
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

进入this.prepareEnvironment(listeners, applicationArguments):


    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        // 从这里跟进去
        listeners.environmentPrepared((ConfigurableEnvironment)environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }

        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }

进入listeners.environmentPrepared((ConfigurableEnvironment)environment):


    public void environmentPrepared(ConfigurableEnvironment environment) {
        Iterator var2 = this.listeners.iterator();

        while(var2.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
            // 从这里跟进去
            listener.environmentPrepared(environment);
        }

    }

进入listener.environmentPrepared(environment):

    public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }

进入this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)):

    public void multicastEvent(ApplicationEvent event) {
        this.multicastEvent(event, this.resolveDefaultEventType(event));
    }

进入this.multicastEvent(event, this.resolveDefaultEventType(event));:


    public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        Iterator var4 = this.getApplicationListeners(event, type).iterator();

        while(var4.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }

    }

进入this.invokeListener(listener, event):

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
            this.doInvokeListener(listener, event);
        }

    }

进入this.doInvokeListener(listener, event):


    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        } catch (ClassCastException var6) {
            String msg = var6.getMessage();
            if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
                throw var6;
            }

            Log logger = LogFactory.getLog(this.getClass());
            if (logger.isDebugEnabled()) {
                logger.debug("Non-matching event type for listener: " + listener, var6);
            }
        }

    }

进入listener.onApplicationEvent(event):

(在org.springframework.boot.context.config.ConfigFileApplicationListener中)

    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
        }

        if (event instanceof ApplicationPreparedEvent) {
            this.onApplicationPreparedEvent(event);
        }

    }

进入this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event):


    private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
        postProcessors.add(this);
        AnnotationAwareOrderComparator.sort(postProcessors);
        Iterator var3 = postProcessors.iterator();

        while(var3.hasNext()) {
            EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
            postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
        }

    }

进入:postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()):

(这里的postProcessors有多个ConfigurableEnvironment的实现类,我们跟入ConfigFileApplicationListener实现类的处理流程)

    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        this.addPropertySources(environment, application.getResourceLoader());
    }

进入this.addPropertySources(environment, application.getResourceLoader()):

    protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        RandomValuePropertySource.addToEnvironment(environment);
        (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
    }

 进入load():

        public void load() {
            this.profiles = new LinkedList();
            this.processedProfiles = new LinkedList();
            this.activatedProfiles = false;
            this.loaded = new LinkedHashMap();
            this.initializeProfiles();

            while(!this.profiles.isEmpty()) {
                ConfigFileApplicationListener.Profile profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
                if (profile != null && !profile.isDefaultProfile()) {
                    this.addProfileToEnvironment(profile.getName());
                }

                this.load(profile, this::getPositiveProfileFilter, this.addToLoaded(MutablePropertySources::addLast, false));
                this.processedProfiles.add(profile);
            }

            this.resetEnvironmentProfiles(this.processedProfiles);
            this.load((ConfigFileApplicationListener.Profile)null, this::getNegativeProfileFilter, this.addToLoaded(MutablePropertySources::addFirst, true));
            this.addLoadedPropertySources();
        }

进入this.load(profile, this::getPositiveProfileFilter, this.addToLoaded(MutablePropertySources::addLast, false)):

        private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
            this.getSearchLocations().forEach((location) -> {
                boolean isFolder = location.endsWith("/");
                Set<String> names = isFolder ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES;
                names.forEach((name) -> {
                    this.load(location, name, profile, filterFactory, consumer);
                });
            });
        }

进入this.load(location, name, profile, filterFactory, consumer):

这里的location目录有四种,我的配置文件放在classpath下:

       private void load(String location, String name, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
            if (!StringUtils.hasText(name)) {
                Iterator var6 = this.propertySourceLoaders.iterator();

                while(var6.hasNext()) {
                    PropertySourceLoader loader = (PropertySourceLoader)var6.next();
                    if (this.canLoadFileExtension(loader, location)) {
                        this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
                        return;
                    }
                }
            }

            Set<String> processed = new HashSet();
            Iterator var14 = this.propertySourceLoaders.iterator();

            while(var14.hasNext()) {
                PropertySourceLoader loaderx = (PropertySourceLoader)var14.next();
                String[] var9 = loaderx.getFileExtensions();
                int var10 = var9.length;

                for(int var11 = 0; var11 < var10; ++var11) {
                    String fileExtension = var9[var11];
                    if (processed.add(fileExtension)) {
                        this.loadForFileExtension(loaderx, location + name, "." + fileExtension, profile, filterFactory, consumer);
                    }
                }
            }

        }

进入this.loadForFileExtension(loaderx, location + name, "." + fileExtension, profile, filterFactory, consumer):


        private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
            ConfigFileApplicationListener.DocumentFilter defaultFilter = filterFactory.getDocumentFilter((ConfigFileApplicationListener.Profile)null);
            ConfigFileApplicationListener.DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
            if (profile != null) {
                String profileSpecificFile = prefix + "-" + profile + fileExtension;
                this.load(loader, profileSpecificFile, profile, defaultFilter, consumer);
                this.load(loader, profileSpecificFile, profile, profileFilter, consumer);
                Iterator var10 = this.processedProfiles.iterator();

                while(var10.hasNext()) {
                    ConfigFileApplicationListener.Profile processedProfile = (ConfigFileApplicationListener.Profile)var10.next();
                    if (processedProfile != null) {
                        String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
                        this.load(loader, previouslyLoaded, profile, profileFilter, consumer);
                    }
                }
            }

            this.load(loader, prefix + fileExtension, profile, profileFilter, consumer);
        }

进入this.load(loader, prefix + fileExtension, profile, profileFilter, consumer):

        private void load(PropertySourceLoader loader, String location, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilter filter, ConfigFileApplicationListener.DocumentConsumer consumer) {
            try {
                Resource resource = this.resourceLoader.getResource(location);
                StringBuilder descriptionxx;
                if (resource != null && resource.exists()) {
                    if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
                        if (this.logger.isTraceEnabled()) {
                            descriptionxx = this.getDescription("Skipped empty config extension ", location, resource, profile);
                            this.logger.trace(descriptionxx);
                        }

                    } else {
                        String name = "applicationConfig: [" + location + "]";
                        List<ConfigFileApplicationListener.Document> documents = this.loadDocuments(loader, name, resource);
                        if (CollectionUtils.isEmpty(documents)) {
                            if (this.logger.isTraceEnabled()) {
                                StringBuilder description = this.getDescription("Skipped unloaded config ", location, resource, profile);
                                this.logger.trace(description);
                            }

                        } else {
                            List<ConfigFileApplicationListener.Document> loaded = new ArrayList();
                            Iterator var10 = documents.iterator();

                            while(var10.hasNext()) {
                                ConfigFileApplicationListener.Document document = (ConfigFileApplicationListener.Document)var10.next();
                                if (filter.match(document)) {
                                    this.addActiveProfiles(document.getActiveProfiles());
                                    this.addIncludedProfiles(document.getIncludeProfiles());
                                    loaded.add(document);
                                }
                            }

                            Collections.reverse(loaded);
                            if (!loaded.isEmpty()) {
                                loaded.forEach((documentx) -> {
                                    consumer.accept(profile, documentx);
                                });
                                if (this.logger.isDebugEnabled()) {
                                    StringBuilder descriptionx = this.getDescription("Loaded config file ", location, resource, profile);
                                    this.logger.debug(descriptionx);
                                }
                            }

                        }
                    }
                } else {
                    if (this.logger.isTraceEnabled()) {
                        descriptionxx = this.getDescription("Skipped missing config ", location, resource, profile);
                        this.logger.trace(descriptionxx);
                    }

                }
            } catch (Exception var12) {
                throw new IllegalStateException("Failed to load property source from location '" + location + "'", var12);
            }
        }

进入this.loadDocuments(loader, name, resource):

        private List<ConfigFileApplicationListener.Document> loadDocuments(PropertySourceLoader loader, String name, Resource resource) throws IOException {
            ConfigFileApplicationListener.DocumentsCacheKey cacheKey = new ConfigFileApplicationListener.DocumentsCacheKey(loader, resource);
            List<ConfigFileApplicationListener.Document> documents = (List)this.loadDocumentsCache.get(cacheKey);
            if (documents == null) {
                List<PropertySource<?>> loaded = loader.load(name, resource);
                documents = this.asDocuments(loaded);
                this.loadDocumentsCache.put(cacheKey, documents);
            }

            return documents;
        }

进入loader.load(name, resource):

(我们用的是properties文件,所以进入PropertiesPropertySourceLoader)

    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        Map<String, ?> properties = this.loadProperties(resource);
        return properties.isEmpty() ? Collections.emptyList() : Collections.singletonList(new OriginTrackedMapPropertySource(name, properties));
    }

进入this.loadProperties(resource):

    private Map<String, ?> loadProperties(Resource resource) throws IOException {
        String filename = resource.getFilename();
        return (Map)(filename != null && filename.endsWith(".xml") ? PropertiesLoaderUtils.loadProperties(resource) : (new OriginTrackedPropertiesLoader(resource)).load());
    }

进入(new OriginTrackedPropertiesLoader(resource)).load()):

    public Map<String, OriginTrackedValue> load() throws IOException {
        return this.load(true);
    }

进入this.load(true):

(ps:终于进入我们要找的地方了)

    public Map<String, OriginTrackedValue> load(boolean expandLists) throws IOException {
        OriginTrackedPropertiesLoader.CharacterReader reader = new OriginTrackedPropertiesLoader.CharacterReader(this.resource);
        Throwable var3 = null;

        try {
            Map<String, OriginTrackedValue> result = new LinkedHashMap();
            StringBuilder buffer = new StringBuilder();

            while(reader.read()) {
                String key = this.loadKey(buffer, reader).trim();
                if (expandLists && key.endsWith("[]")) {
                    key = key.substring(0, key.length() - 2);
                    int var19 = 0;

                    while(true) {
                        OriginTrackedValue value = this.loadValue(buffer, reader, true);
                        this.put(result, key + "[" + var19++ + "]", value);
                        if (!reader.isEndOfLine()) {
                            reader.read();
                        }

                        if (reader.isEndOfLine()) {
                            break;
                        }
                    }
                } else {
                    OriginTrackedValue value = this.loadValue(buffer, reader, false);
                    this.put(result, key, value);
                }
            }

            LinkedHashMap var18 = result;
            return var18;
        } catch (Throwable var16) {
            var3 = var16;
            throw var16;
        } finally {
            if (reader != null) {
                if (var3 != null) {
                    try {
                        reader.close();
                    } catch (Throwable var15) {
                        var3.addSuppressed(var15);
                    }
                } else {
                    reader.close();
                }
            }

        }
    }

分别看下loadKey和loadValue方法:

loadKey:

    private String loadKey(StringBuilder buffer, OriginTrackedPropertiesLoader.CharacterReader reader) throws IOException {
        buffer.setLength(0);
        boolean previousWhitespace = false;

        while(!reader.isEndOfLine()) {
            if (reader.isPropertyDelimiter()) {
                reader.read();
                return buffer.toString();
            }
            // 从这里的判断逻辑可以发现,配置文件的key不能被空白字符分隔
            if (!reader.isWhiteSpace() && previousWhitespace) {
                return buffer.toString();
            }

            previousWhitespace = reader.isWhiteSpace();
            buffer.append(reader.getCharacter());
            reader.read();
        }

        return buffer.toString();
    }

loadValue:

    private OriginTrackedValue loadValue(StringBuilder buffer, OriginTrackedPropertiesLoader.CharacterReader reader, boolean splitLists) throws IOException {
        buffer.setLength(0);
        // 分隔符(:和=)后面的空白字符全部跳过
        while(reader.isWhiteSpace() && !reader.isEndOfLine()) {
            reader.read();
        }

        Location location = reader.getLocation();

        while(!reader.isEndOfLine() && (!splitLists || !reader.isListDelimiter())) {
            buffer.append(reader.getCharacter());
            reader.read();
        }

        Origin origin = new TextResourceOrigin(this.resource, location);
        return OriginTrackedValue.of(buffer.toString(), origin);
    }

可以看到,对于key,会去掉前后空格(reader.read()方法,对于开头的空白字符会跳过,所以key左边的空白字符是读出来的时候已经去掉了);对于value,value左边的空白字符会被忽略,但是右边的空白字符会被保留:

配置文件:

 读取到的配置:

 

 

参考文章:

SpringBoot读取配置文件源码探究

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值