{"id":1884,"date":"2019-06-12T08:02:35","date_gmt":"2019-06-12T00:02:35","guid":{"rendered":"https:\/\/coderbee.net\/?p=1884"},"modified":"2019-06-11T09:32:52","modified_gmt":"2019-06-11T01:32:52","slug":"springboot-%e5%90%af%e5%8a%a8%e5%88%86%e6%9e%90%e4%b8%89-environment-%e7%9a%84%e5%88%9d%e5%a7%8b%e5%8c%96%e6%b5%81%e7%a8%8b","status":"publish","type":"post","link":"https:\/\/coderbee.net\/index.php\/framework\/20190612\/1884","title":{"rendered":"SpringBoot \u542f\u52a8\u5206\u6790(\u4e09) &#8212; Environment \u7684\u521d\u59cb\u5316\u6d41\u7a0b"},"content":{"rendered":"<h1>1. Environment \u7684\u521d\u59cb\u5316\u6d41\u7a0b<\/h1>\n<p><code>ConfigFileApplicationListener<\/code> \u6536\u5230 <code>ApplicationEnvironmentPreparedEvent<\/code> \u4e8b\u4ef6\u540e\u901a\u8fc7 SPI \u52a0\u8f7d\u6240\u6709\u7684 <code>EnvironmentPostProcessor<\/code> \u5b9e\u73b0\uff0c\u89e6\u53d1\u5176 <code>postProcessEnviroment<\/code> \u65b9\u6cd5\u3002<\/p>\n<pre><code>SpringApplication.run() -&gt;\nSpringFactoriesLoader.loadFactories(ApplicationListener) -&gt;\nSpringApplication.prepareEnviroment() -&gt; EventPublishingRunListener.enviromentPrepared(ApplicationEnviromentPraparedEvent) -&gt;\nSimpleApplicationEventMulticaster.multicastEvent() -&gt;\nConfigFileApplicationListener.onApplicationOnEnviromentPreparedEvent() -&gt;\nEnviromentPostProcessor.postProcessEnviroment()\n<\/code><\/pre>\n<p>\u6bd4\u8f83\u91cd\u8981\u7684 <code>EnviromentPostProcessor<\/code> \u5b9e\u73b0\u662f <code>HostInfoEnvironmentPostProcessor<\/code> \u548c <code>ConfigFileApplicationListener<\/code>\u3002<\/p>\n<h1>2. HostInfoEnvironmentPostProcessor.postProcessEnviroment<\/h1>\n<p>\u83b7\u53d6\u672c\u673a\u7684 \u4e3b\u673a\u540d\u548cIP\u5730\u5740\uff0c\u5c01\u88c5\u5728 <code>PropertySource<\/code> \u6dfb\u52a0\u5230 environment \u91cc\u3002<\/p>\n<h1>3. ConfigFileApplicationListener.postProcessEnviroment<\/h1>\n<p><code>ConfigFileApplicationListener<\/code> \u81ea\u8eab\u4e5f\u5b9e\u73b0\u4e86 <code>EnvironmentPostProcessor<\/code>\uff0c\u901a\u8fc7\u5185\u90e8\u7c7b Loader \u53bb\u52a0\u8f7d\u914d\u7f6e\u6587\u4ef6\uff0c\u5176\u4e3b\u8981\u6d41\u7a0b\u5982\u4e0b\uff1a<\/p>\n<ol>\n<li>\u4ece Environment \u4e2d\u83b7\u53d6 active \u548c include \u7684 profile \u96c6\u5408\u3002\u8fdb\u884c\u8fed\u4ee3\uff1a<\/li>\n<li>\u83b7\u53d6\u6240\u6709\u7684\u641c\u7d22\u8def\u5f84\uff0c\u8fdb\u884c\u8fed\u4ee3\uff0c\u9ed8\u8ba4\u7684\u641c\u7d22\u8def\u5f84\u662f <code>classpath:\/,classpath:\/config\/,file:.\/,file:.\/config\/<\/code> \u3002<\/li>\n<li>\u5982\u679c\u67d0\u4e2a\u641c\u7d22\u8def\u5f84\u4e0d\u4ee5 <code>\/<\/code> \u7ed3\u5c3e\u7684\u5219\u8ba4\u4e3a\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u76f4\u63a5\u52a0\u8f7d\uff0c\u5426\u5219\uff0c\u627e\u51fa\u6240\u6709\u7684\u641c\u7d22\u6587\u4ef6\u540d name \u8fdb\u884c\u8fed\u4ee3\u641c\u7d22\uff0c\u9ed8\u8ba4\u7684\u641c\u7d22\u6587\u4ef6\u540d\u662f &#8220;application&#8221;\u3002<\/li>\n<li>\u901a\u8fc7 <code>PropertySourcesLoader<\/code> \u627e\u51fa\u652f\u6301\u7684\u6240\u6709\u914d\u7f6e\u6587\u4ef6\u540e\u7f00\u8fdb\u884c\u8fed\u4ee3\u3002<\/li>\n<li>\u6700\u7ec8\u5f97\u5230 <code>location + name + \"-\" + profile + \".\" + ext<\/code> \u7ec4\u6210\u7684\u4e00\u4e2a\u5177\u4f53\u7684\u5b8c\u6574\u8def\u5f84\uff0c\u901a\u8fc7 <code>PropertiesLoader.load<\/code> \u65b9\u6cd5\u52a0\u8f7d\u8be5\u8def\u5f84\u6307\u5411\u7684\u914d\u7f6e\u6587\u4ef6\u3002<\/li>\n<li><code>PropertiesLoader.load<\/code> \u5185\u90e8\u53c8\u6839\u636e\u914d\u7f6e\u6587\u4ef6\u7684\u540e\u7f00\u7528\u4e0d\u540c\u7684 <code>PropertySourceLoader<\/code> \u53bb\u52a0\u8f7d\u5f97\u5230\u4e00\u4e2a <code>PropertySource<\/code> \u3002<\/li>\n<li>\u5bf9\u4e8e\u89e3\u6790\u5f97\u5230\u7684 <code>PropertySource<\/code>\uff0c\u627e\u51fa\u91cc\u9762\u6fc0\u6d3b\u7684 profile\uff0c\u6dfb\u52a0\u5230 proflie \u96c6\u5408\u91cc\u8fdb\u884c\u8fed\u4ee3\u3002<\/li>\n<li>\u7ee7\u7eed\u8fed\u4ee3\u4e0b\u4e00\u4e2a profile \u3002<\/li>\n<\/ol>\n<p><!--more--><\/p>\n<h2>3.1 PropertySourceLoader<\/h2>\n<p><code>PropertySourceLoader<\/code> \u662f\u7528\u6765\u52a0\u8f7d <code>PropertySource<\/code> \u7684\u4e00\u4e2a\u7b56\u7565\u63a5\u53e3\uff0c\u6709\u4e24\u4e2a\u5177\u4f53\u7684\u5b9e\u73b0\u7c7b <code>PropertiesPropertySourceLoader<\/code> \u548c <code>YamlPropertySourceLoader<\/code>\uff0c\u524d\u8005\u7528\u4e8e\u52a0\u8f7d <code>properties\/xml<\/code> \u540e\u7f00\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u540e\u8005\u7528\u4e8e\u52a0\u8f7d <code>yml<\/code> \u540e\u8005\u7684\u914d\u7f6e\u6587\u4ef6\u3002<\/p>\n<h2>3.2 PropertySourcesLoader<\/h2>\n<p><code>PropertySourcesLoader<\/code> \u662f\u4e00\u4e2a facade \u7c7b\uff0c\u901a <code>SpringFactoriesLoader<\/code> \u52a0\u8f7d <code>PropertySourceLoader<\/code> \u7684\u6240\u6709\u5b9e\u73b0\u7c7b\u3002\u5728\u5b83\u7684 load \u65b9\u6cd5\u91cc\u4f1a\u8fed\u4ee3\u8fd9\u4e9b\u5b9e\u73b0\u7c7b\u4ee5\u52a0\u8f7d\u7279\u5b9a\u540e\u7f00\u7684\u914d\u7f6e\u6587\u4ef6\u3002<\/p>\n<pre><code class=\"java\">public PropertySourcesLoader(MutablePropertySources propertySources) {\n    Assert.notNull(propertySources, \"PropertySources must not be null\");\n    this.propertySources = propertySources;\n    this.loaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());\n}\n\npublic PropertySource&lt;?&gt; load(Resource resource, String group, String name,\n        String profile) throws IOException {\n    if (isFile(resource)) {\n        String sourceName = generatePropertySourceName(name, profile);\n\n        for (PropertySourceLoader loader : this.loaders) {\n            if (canLoadFileExtension(loader, resource)) {\n                PropertySource&lt;?&gt; specific = loader.load(sourceName, resource, profile);\n                addPropertySource(group, specific);\n                return specific;\n            }\n        }\n    }\n    return null;\n}\n\nprivate void addPropertySource(String basename, PropertySource&lt;?&gt; source) {\n    if (source == null) {\n        return;\n    }\n    if (basename == null) {\n        this.propertySources.addLast(source);\n        return;\n    }\n\n    EnumerableCompositePropertySource group = getGeneric(basename);\n    group.add(source);\n    logger.trace(\"Adding PropertySource: \" + source + \" in group: \" + basename);\n\n    if (this.propertySources.contains(group.getName())) {\n        \/\/ \u66ff\u6362\u539f\u6709\u7684\n        this.propertySources.replace(group.getName(), group);\n    } else {\n        \/\/ \u628a\u6700\u65b0\u7684\u6dfb\u52a0\u5230\u5217\u8868\u7684\u9996\u90e8\n        \/\/ \u5bf9\u4e8e PropertiesPropertySourceLoader\uff0c properties \u540e\u7f00\u7684\u6bd4 xml \u7684\u5148\u52a0\u8f7d\uff0c\u4f18\u5148\u7ea7\u53cd\u800c\u4f4e\u4e86\n        this.propertySources.addFirst(group);\n    }\n}\n<\/code><\/pre>\n<h2>3.3 Loader \u52a0\u8f7d\u914d\u7f6e\u7684\u6e90\u7801<\/h2>\n<pre><code class=\"java\">\/\/ \u52a0\u8f7d\u5c5e\u6027\u6e90\u5230 enviroment\nprotected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {\n    \/\/ \u628a\u968f\u673a\u503c\u7684\u5c5e\u6027\u6e90\u6dfb\u52a0\u5230 enviroment\n    RandomValuePropertySource.addToEnvironment(environment);\n\n    \/\/ \u4ece\u914d\u7f6e\u6587\u4ef6\u52a0\u8f7d\u5c5e\u6027\u6e90\u5230 environment \n    new Loader(environment, resourceLoader).load();\n}\n\n\/\/ Loader \u7c7b\npublic void load() {\n    this.propertiesLoader = new PropertySourcesLoader();\n    this.activatedProfiles = false;\n    this.profiles = Collections.asLifoQueue(new LinkedList&lt;Profile&gt;());\n    this.processedProfiles = new LinkedList&lt;Profile&gt;();\n\n    \/\/ Pre-existing active profiles set via Environment.setActiveProfiles()\n    \/\/ are additional profiles and config files are allowed to add more if\n    \/\/ they want to, so don't call addActiveProfiles() here.\n    \/\/ \u6dfb\u52a0\u5df2\u5b58\u5728\u3001\u6fc0\u6d3b\u7684 profiles\n    Set&lt;Profile&gt; initialActiveProfiles = initializeActiveProfiles();\n    this.profiles.addAll(getUnprocessedActiveProfiles(initialActiveProfiles));\n    if (this.profiles.isEmpty()) {\n        for (String defaultProfileName : this.environment.getDefaultProfiles()) {\n            Profile defaultProfile = new Profile(defaultProfileName, true);\n            if (!this.profiles.contains(defaultProfile)) {\n                this.profiles.add(defaultProfile);\n            }\n        }\n    }\n\n    \/\/ \u8fed\u4ee3\u8fc7\u7a0b\u4e2d\u9ed8\u8ba4\u7684 proflie \u7528 null \u8868\u793a\u3002\u6dfb\u52a0\u5230\u6700\u540e\u53ef\u4ee5\u7b2c\u4e00\u4e2a\u51fa\u961f\u5217\u3002\n    \/\/ \u540e\u9762\u8fed\u4ee3\u7684\u6fc0\u6d3b\u7684 profiles \u4f1a\u8986\u5199\u9ed8\u8ba4\u7684\u914d\u7f6e\n    this.profiles.add(null);\n\n    \/\/ \u8fed\u4ee3 proflie\n    while (!this.profiles.isEmpty()) {\n        Profile profile = this.profiles.poll();\n        \/\/ \u8fed\u4ee3\u8981\u641c\u7d22\u7684\u8def\u5f84\n        for (String location : getSearchLocations()) {\n            if (!location.endsWith(\"\/\")) {\n                \/\/ location is a filename already, so don't search for more filenames\n                load(location, null, profile);\n            } else {\n                \/\/ \u8fed\u4ee3\u8981\u641c\u7d22\u7684\u914d\u7f6e\u6587\u4ef6\u540d\n                for (String name : getSearchNames()) {\n                    load(location, name, profile);\n                }\n            }\n        }\n        this.processedProfiles.add(profile);\n    }\n\n    \/\/ \u628a\u52a0\u8f7d\u5230\u7684 PropertySources \u6dfb\u52a0\u5230 enviroment\n    addConfigurationProperties(this.propertiesLoader.getPropertySources());\n}\n\nprivate void load(String location, String name, Profile profile) {\n    String group = \"profile=\" + ((profile != null) ? profile : \"\");\n    if (!StringUtils.hasText(name)) {\n        \/\/ Try to load directly from the location\n        loadIntoGroup(group, location, profile);\n    }\n    else {\n        \/\/ \u8fed\u4ee3\u6240\u6709\u652f\u6301\u7684\u6587\u4ef6\u540e\u7f00\n        for (String ext : this.propertiesLoader.getAllFileExtensions()) {\n            if (profile != null) {\n                \/\/ \u5c1d\u8bd5 profile \u7279\u5b9a\u7684\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u5305\u542b proflie \u503c\u7684\n                loadIntoGroup(group, location + name + \"-\" + profile + \".\" + ext, null);\n                for (Profile processedProfile : this.processedProfiles) {\n                    if (processedProfile != null) {\n                        loadIntoGroup(group, location + name + \"-\" + processedProfile + \".\" + ext, profile);\n                    }\n                }\n                \/\/ Sometimes people put \"spring.profiles: dev\" in\n                \/\/ application-dev.yml (gh-340). Arguably we should try and error\n                \/\/ out on that, but we can be kind and load it anyway.\n                loadIntoGroup(group, location + name + \"-\" + profile + \".\" + ext, profile);\n            }\n            \/\/ Also try the profile-specific section (if any) of the normal file\n            loadIntoGroup(group, location + name + \".\" + ext, profile);\n        }\n    }\n}\n\n\/\/ \u5982\u679c\u89e3\u6790\u7684\u914d\u7f6e\u6587\u4ef6\u91cc\u7528 spring.config.location \u6307\u5b9a\u4e86\u65b0\u7684\u4f4d\u7f6e\uff0c\n\/\/ \u90a3\u4e48\u4e0b\u4e00\u8f6e\u67e5\u627e\u4e5f\u628a spring.config.location \u5c5e\u6027\u6307\u5b9a\u7684\u4f4d\u7f6e\u52a0\u5165\u641c\u7d22\u8303\u56f4\n\/\/ \u9ed8\u8ba4\u7684\u641c\u7d22\u4f4d\u7f6e\u6709: classpath:\/,classpath:\/config\/,file:.\/,file:.\/config\/\nprivate Set&lt;String&gt; getSearchLocations() {\n    Set&lt;String&gt; locations = new LinkedHashSet&lt;String&gt;();\n    \/\/ User-configured settings take precedence, so we do them first\n    if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {\n        for (String path : asResolvedSet(\n                this.environment.getProperty(CONFIG_LOCATION_PROPERTY), null)) {\n            if (!path.contains(\"$\")) {\n                path = StringUtils.cleanPath(path);\n                if (!ResourceUtils.isUrl(path)) {\n                    path = ResourceUtils.FILE_URL_PREFIX + path;\n                }\n            }\n            locations.add(path);\n        }\n    }\n\n    \/\/ DEFAULT_SEARCH_LOCATIONS\uff1aNote the order is from least to most specific (last one wins)\n    \/\/ asResolvedSet \u4f1a\u8fdb\u884c\u9006\u5e8f\u64cd\u4f5c\n    locations.addAll(asResolvedSet(ConfigFileApplicationListener.this.searchLocations,\n                    DEFAULT_SEARCH_LOCATIONS));\n    return locations;\n}\n\n\/\/ \u5982\u679c\u6709\u3001\u5219\u7528 spring.config.name \u5c5e\u6027\u6307\u5b9a\u914d\u7f6e\u6587\u4ef6\u540d\uff0c\n\/\/ \u5426\u5219\u7528\u9ed8\u8ba4\u7684\u914d\u7f6e\u6587\u4ef6\u540d\u662f application\nprivate Set&lt;String&gt; getSearchNames() {\n    if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {\n        return asResolvedSet(this.environment.getProperty(CONFIG_NAME_PROPERTY), null);\n    }\n    return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);\n}\n\nprivate Set&lt;String&gt; asResolvedSet(String value, String fallback) {\n    List&lt;String&gt; list = Arrays.asList(StringUtils.trimArrayElements(\n            StringUtils.commaDelimitedListToStringArray(value != null\n                    ? this.environment.resolvePlaceholders(value) : fallback)));\n    Collections.reverse(list);\n    return new LinkedHashSet&lt;String&gt;(list);\n}\n\n\/\/ load \u65b9\u6cd5\u4f1a\u8c03\u7528\u5230\u8fd9\u91cc\u6765\u52a0\u8f7d\u5c5e\u6027\u6e90\uff0c\u5220\u9664\u4e86\u4e00\u4e9btrace\u65e5\u5fd7\u76f8\u5173\u7684\u4ee3\u7801\nprivate PropertySource&lt;?&gt; doLoadIntoGroup(String identifier, String location,\n        Profile profile) throws IOException {\n    Resource resource = this.resourceLoader.getResource(location);\n    PropertySource&lt;?&gt; propertySource = null;\n    if (resource != null &amp;&amp; resource.exists()) {\n        String name = \"applicationConfig: [\" + location + \"]\";\n        String group = \"applicationConfig: [\" + identifier + \"]\";\n\n        \/\/ propertiesLoader.load \u4f7f\u7528 PropertiesPropertySourceLoader\/YamlPropertySourceLoader \u5bf9\u8d44\u6e90\u8fdb\u884c\u52a0\u8f7d\n        propertySource = this.propertiesLoader.load (resource, group, name,\n                (profile == null ? null : profile.getName()));\n        if (propertySource != null) {\n            handleProfileProperties(propertySource);\n        }\n    }\n    return propertySource;\n}\n\nprivate void addConfigurationProperties(MutablePropertySources sources) {\n    List&lt;PropertySource&lt;?&gt;&gt; reorderedSources = new ArrayList&lt;PropertySource&lt;?&gt;&gt;();\n    for (PropertySource&lt;?&gt; item : sources) {\n        reorderedSources.add(item);\n    }\n    addConfigurationProperties(new ConfigurationPropertySources(reorderedSources));\n}\n\nprivate void addConfigurationProperties(ConfigurationPropertySources configurationSources) {\n    MutablePropertySources existingSources = this.environment.getPropertySources();\n    if (existingSources.contains(DEFAULT_PROPERTIES)) {\n        \/\/ \u8986\u76d6\u9ed8\u8ba4\u7684\u5c5e\u6027\u6e90\n        existingSources.addBefore(DEFAULT_PROPERTIES, configurationSources);\n    } else {\n        \/\/ \u524d\u9762\u52a0\u8f7d\u7684\u6bd4\u540e\u9762\u52a0\u8f7d\u7684\u4f18\u5148\u7ea7\u9ad8\n        existingSources.addLast(configurationSources);\n    }\n}\n<\/code><\/pre>\n<p>\u4e0d\u540c\u7684\u641c\u7d22\u3001\u52a0\u8f7d\u987a\u5e8f\u51b3\u5b9a\u4e86\u914d\u7f6e\u6587\u4ef6\u7684\u4e0d\u540c\u4f18\u5148\u7ea7\uff1a<\/p>\n<ol>\n<li>\u6240\u6709\u914d\u7f6e\u6587\u4ef6\u7684\u914d\u7f6e\u90fd\u6bd4\u9ed8\u8ba4\u914d\u7f6e\u7684\u4f18\u5148\u7ea7\u9ad8\uff1b<\/li>\n<li>\u5148\u52a0\u8f7d\u7684\u6bd4\u540e\u52a0\u8f7d\u7684\u4f18\u5148\u7ea7\u9ad8\uff1b<\/li>\n<li>\u5bf9\u4e8e <code>PropertiesPropertySourceLoader<\/code> \u52a0\u8f7d\u540c\u4e00\u4e2a\u6587\u4ef6\u540d\uff0c<code>properties<\/code> \u540e\u7f00\u7684\u6bd4 <code>xml<\/code> \u7684\u5148\u52a0\u8f7d\uff0c\u4f18\u5148\u7ea7\u53cd\u800c\u4f4e\u4e86\u3002<\/li>\n<\/ol>\n<hr \/>\n<p>\u6b22\u8fce\u5173\u6ce8\u6211\u7684\u5fae\u4fe1\u516c\u4f17\u53f7: <strong>coderbee\u7b14\u8bb0<\/strong>\uff0c\u53ef\u4ee5\u66f4\u53ca\u65f6\u56de\u590d\u4f60\u7684\u8ba8\u8bba\u3002<br \/>\n<img loading=\"lazy\" decoding=\"async\" width=\"258\" height=\"258\" src=\"https:\/\/coderbee.net\/wp-content\/uploads\/2019\/01\/coderbee-note.jpg\" class=\"alignnone size-full wp-image-1707\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. Environment \u7684\u521d\u59cb\u5316\u6d41\u7a0b ConfigFileApplicat &hellip; <a href=\"https:\/\/coderbee.net\/index.php\/framework\/20190612\/1884\">\u7ee7\u7eed\u9605\u8bfb <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[255],"tags":[172,308],"_links":{"self":[{"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/posts\/1884"}],"collection":[{"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/comments?post=1884"}],"version-history":[{"count":2,"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/posts\/1884\/revisions"}],"predecessor-version":[{"id":1886,"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/posts\/1884\/revisions\/1886"}],"wp:attachment":[{"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/media?parent=1884"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/categories?post=1884"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/coderbee.net\/index.php\/wp-json\/wp\/v2\/tags?post=1884"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}