Browse Source

CN.1875084792839892:9376a8f5cdbd84c02ee5939b99566c24_693016fa3893af23b22a8404.693017423893af23b22a8408.693017429cfd2bfc0de4d707:Trae CN.T(2025/12/3 18:56:02)

pull/48384/head
huanghu 2 weeks ago
parent
commit
c366908db2
  1. 39
      core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotAutoConfiguration.java
  2. 128
      core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotListener.java
  3. 74
      core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotProperties.java
  4. 18
      core/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
  5. 4
      core/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
  6. 74
      core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotAutoConfigurationTests.java

39
core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotAutoConfiguration.java

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.context;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* Auto-configuration for configuration snapshot logging.
*
* @author Your Name
* @since 3.2.0
*/
@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.config-snapshot", name = "enabled", havingValue = "true")
@EnableConfigurationProperties(ConfigurationSnapshotProperties.class)
public class ConfigurationSnapshotAutoConfiguration {
@Bean
public ConfigurationSnapshotListener configurationSnapshotListener(ConfigurationSnapshotProperties properties) {
return new ConfigurationSnapshotListener(properties);
}
}

128
core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotListener.java

@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.context;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
/**
* Application listener that logs a snapshot of the application configuration when the
* context is refreshed.
*
* @author Your Name
* @since 3.2.0
*/
public class ConfigurationSnapshotListener implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger logger = LoggerFactory.getLogger(ConfigurationSnapshotListener.class);
private final ConfigurationSnapshotProperties properties;
public ConfigurationSnapshotListener(ConfigurationSnapshotProperties properties) {
this.properties = properties;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Environment environment = event.getApplicationContext().getEnvironment();
if (!(environment instanceof ConfigurableEnvironment configurableEnvironment)) {
return;
}
// Build configuration snapshot
Map<String, Object> snapshot = new HashMap<>();
snapshot.put("activeProfiles", environment.getActiveProfiles());
Map<String, String> includedProperties = new HashMap<>();
if (this.properties.getInclude() != null && !this.properties.getInclude().isEmpty()) {
for (String propertyName : this.properties.getInclude()) {
if (environment.containsProperty(propertyName)) {
includedProperties.put(propertyName, environment.getProperty(propertyName));
}
}
}
snapshot.put("properties", includedProperties);
// Convert to JSON
String json = toJson(snapshot);
// Log to console or file
if (this.properties.getLogTo() == ConfigurationSnapshotProperties.LogTo.CONSOLE) {
logger.info("Configuration snapshot: {}", json);
} else {
writeToFile(json);
}
}
private String toJson(Map<String, Object> snapshot) {
StringBuilder sb = new StringBuilder();
sb.append("{");
// Active profiles
sb.append("\"activeProfiles\": [");
String[] activeProfiles = (String[]) snapshot.get("activeProfiles");
for (int i = 0; i < activeProfiles.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append("\"").append(activeProfiles[i]).append("\"");
}
sb.append("]");
// Properties
sb.append(",\"properties\": {");
Map<String, String> properties = (Map<String, String>) snapshot.get("properties");
int i = 0;
for (Map.Entry<String, String> entry : properties.entrySet()) {
if (i > 0) {
sb.append(",");
}
sb.append("\"").append(entry.getKey()).append("\":\"").append(entry.getValue()).append("\"");
i++;
}
sb.append("}");
sb.append("}");
return sb.toString();
}
private void writeToFile(String json) {
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String filename = "config-snapshot-" + timestamp + ".log";
try (FileWriter writer = new FileWriter(filename)) {
writer.write(json);
logger.info("Configuration snapshot written to file: {}", filename);
} catch (IOException e) {
logger.error("Failed to write configuration snapshot to file: {}", filename, e);
}
}
}

74
core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotProperties.java

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.context;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for configuration snapshot logging.
*
* @author Your Name
* @since 3.2.0
*/
@ConfigurationProperties(prefix = "spring.config-snapshot")
public class ConfigurationSnapshotProperties {
/**
* Whether to enable configuration snapshot logging.
*/
private boolean enabled = false;
/**
* Where to log the configuration snapshot.
*/
private LogTo logTo = LogTo.CONSOLE;
/**
* List of properties to include in the snapshot.
*/
private List<String> include;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public LogTo getLogTo() {
return this.logTo;
}
public void setLogTo(LogTo logTo) {
this.logTo = logTo;
}
public List<String> getInclude() {
return this.include;
}
public void setInclude(List<String> include) {
this.include = include;
}
public enum LogTo {
CONSOLE, FILE
}
}

18
core/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

@ -1,6 +1,24 @@ @@ -1,6 +1,24 @@
{
"groups": [],
"properties": [
{
"name": "spring.config-snapshot.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable configuration snapshot logging.",
"defaultValue": false
},
{
"name": "spring.config-snapshot.log-to",
"type": "org.springframework.boot.autoconfigure.context.ConfigurationSnapshotProperties.LogTo",
"description": "Where to log the configuration snapshot.",
"defaultValue": "CONSOLE"
},
{
"name": "spring.config-snapshot.include",
"type": "java.util.List<java.lang.String>",
"description": "List of properties to include in the snapshot.",
"defaultValue": []
},
{
"name": "spring.aop.auto",
"type": "java.lang.Boolean",

4
core/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

@ -26,3 +26,7 @@ org.springframework.boot.autoconfigure.preinitialize.ConversionServiceBackground @@ -26,3 +26,7 @@ org.springframework.boot.autoconfigure.preinitialize.ConversionServiceBackground
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.ssl.BundleContentNotWatchableFailureAnalyzer
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.context.ConfigurationSnapshotAutoConfiguration

74
core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/ConfigurationSnapshotAutoConfigurationTests.java

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.context;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ConfigurationSnapshotAutoConfiguration}.
*
* @author Your Name
* @since 3.2.0
*/
class ConfigurationSnapshotAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(
AutoConfigurations.of(ConfigurationSnapshotAutoConfiguration.class));
@Test
void configurationSnapshotAutoConfigurationIsDisabledByDefault() {
this.contextRunner.run((context) -> {
assertThat(context.getBeansOfType(ConfigurationSnapshotListener.class)).isEmpty();
});
}
@Test
void configurationSnapshotAutoConfigurationIsEnabledWhenPropertyIsSetToTrue() {
this.contextRunner.withPropertyValues("spring.config-snapshot.enabled=true")
.run((context) -> {
assertThat(context.getBeansOfType(ConfigurationSnapshotListener.class)).isNotEmpty();
});
}
@Test
void configurationSnapshotAutoConfigurationIsDisabledWhenPropertyIsSetToFalse() {
this.contextRunner.withPropertyValues("spring.config-snapshot.enabled=false")
.run((context) -> {
assertThat(context.getBeansOfType(ConfigurationSnapshotListener.class)).isEmpty();
});
}
@Test
void configurationSnapshotPropertiesAreBoundCorrectly() {
this.contextRunner.withPropertyValues(
"spring.config-snapshot.enabled=true",
"spring.config-snapshot.log-to=FILE",
"spring.config-snapshot.include=spring.datasource.url,spring.cache.enabled")
.run((context) -> {
ConfigurationSnapshotProperties properties = context.getBean(ConfigurationSnapshotProperties.class);
assertThat(properties.isEnabled()).isTrue();
assertThat(properties.getLogTo()).isEqualTo(ConfigurationSnapshotProperties.LogTo.FILE);
assertThat(properties.getInclude()).containsExactly("spring.datasource.url", "spring.cache.enabled");
});
}
}
Loading…
Cancel
Save