1.云支持
private static final String VCAP_APPLICATION = "VCAP_APPLICATION";
private static final String VCAP_SERVICES = "VCAP_SERVICES";
private final Log logger;
// Before ConfigDataEnvironmentPostProcessor so values there can use these
private int order = ConfigDataEnvironmentPostProcessor.ORDER - 1;
/**
* Create a new {@link CloudFoundryVcapEnvironmentPostProcessor} instance.
* @param logFactory the log factory to use
* @since 3.0.0
*/
public CloudFoundryVcapEnvironmentPostProcessor(DeferredLogFactory logFactory) {
this.logger = logFactory.getLog(CloudFoundryVcapEnvironmentPostProcessor.class);
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {
Properties properties = new Properties();
JsonParser jsonParser = JsonParserFactory.getJsonParser();
addWithPrefix(properties, getPropertiesFromApplication(environment, jsonParser), "vcap.application.");
addWithPrefix(properties, getPropertiesFromServices(environment, jsonParser), "vcap.services.");
MutablePropertySources propertySources = environment.getPropertySources();
if (propertySources.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
propertySources.addAfter(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
new PropertiesPropertySource("vcap", properties));
}
else {
propertySources.addFirst(new PropertiesPropertySource("vcap", properties));
}
}
}
private void addWithPrefix(Properties properties, Properties other, String prefix) {
for (String key : other.stringPropertyNames()) {
String prefixed = prefix + key;
properties.setProperty(prefixed, other.getProperty(key));
}
}
private Properties getPropertiesFromApplication(Environment environment, JsonParser parser) {
Properties properties = new Properties();
try {
String property = environment.getProperty(VCAP_APPLICATION, "{}");
Map<String, Object> map = parser.parseMap(property);
extractPropertiesFromApplication(properties, map);
}
catch (Exception ex) {
this.logger.error("Could not parse VCAP_APPLICATION", ex);
}
return properties;
}
private Properties getPropertiesFromServices(Environment environment, JsonParser parser) {
Properties properties = new Properties();
try {
String property = environment.getProperty(VCAP_SERVICES, "{}");
Map<String, Object> map = parser.parseMap(property);
extractPropertiesFromServices(properties, map);
}
catch (Exception ex) {
this.logger.error("Could not parse VCAP_SERVICES", ex);
}
return properties;
}
private void extractPropertiesFromApplication(Properties properties, Map<String, Object> map) {
if (map != null) {
flatten(properties, map, "");
}
}
private void extractPropertiesFromServices(Properties properties, Map<String, Object> map) {
if (map != null) {
for (Object services : map.values()) {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>) services;
for (Object object : list) {
@SuppressWarnings("unchecked")
Map<String, Object> service = (Map<String, Object>) object;
String key = (String) service.get("name");
if (key == null) {
key = (String) service.get("label");
}
flatten(properties, service, key);
}
}
}
}
@SuppressWarnings("unchecked")
private void flatten(Properties properties, Map<String, Object> input, String path) {
input.forEach((key, value) -> {
String name = getPropertyName(path, key);
if (value instanceof Map) {
// Need a compound key
flatten(properties, (Map<String, Object>) value, name);
}
else if (value instanceof Collection) {
// Need a compound key
Collection<Object> collection = (Collection<Object>) value;
properties.put(name, StringUtils.collectionToCommaDelimitedString(collection));
int count = 0;
for (Object item : collection) {
String itemKey = "[" + (count++) + "]";
flatten(properties, Collections.singletonMap(itemKey, item), name);
}
}
else if (value instanceof String) {
properties.put(name, value);
}
else if (value instanceof Number) {
properties.put(name, value.toString());
}
else if (value instanceof Boolean) {
properties.put(name, value.toString());
}
else {
properties.put(name, (value != null) ? value : "");
}
});
}
private String getPropertyName(String path, String key) {
if (!StringUtils.hasText(path)) {
return key;
}
if (key.startsWith("[")) {
return path + key;
}
return path + "." + key;
}
2.原生云平台支持:
/**
* No Cloud platform. Useful when false-positives are detected.
*/
NONE {
@Override
public boolean isDetected(Environment environment) {
return false;
}
},
/**
* Cloud Foundry platform.
*/
CLOUD_FOUNDRY {
@Override
public boolean isDetected(Environment environment) {
return environment.containsProperty("VCAP_APPLICATION") || environment.containsProperty("VCAP_SERVICES");
}
},
/**
* Heroku platform.
*/
HEROKU {
@Override
public boolean isDetected(Environment environment) {
return environment.containsProperty("DYNO");
}
},
/**
* SAP Cloud platform.
*/
SAP {
@Override
public boolean isDetected(Environment environment) {
return environment.containsProperty("HC_LANDSCAPE");
}
},
/**
* Kubernetes platform.
*/
KUBERNETES {
private static final String KUBERNETES_SERVICE_HOST = "KUBERNETES_SERVICE_HOST";
private static final String KUBERNETES_SERVICE_PORT = "KUBERNETES_SERVICE_PORT";
private static final String SERVICE_HOST_SUFFIX = "_SERVICE_HOST";
private static final String SERVICE_PORT_SUFFIX = "_SERVICE_PORT";
@Override
public boolean isDetected(Environment environment) {
if (environment instanceof ConfigurableEnvironment configurableEnvironment) {
return isAutoDetected(configurableEnvironment);
}
return false;
}
private boolean isAutoDetected(ConfigurableEnvironment environment) {
PropertySource<?> environmentPropertySource = environment.getPropertySources()
.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
if (environmentPropertySource != null) {
if (environmentPropertySource.containsProperty(KUBERNETES_SERVICE_HOST)
&& environmentPropertySource.containsProperty(KUBERNETES_SERVICE_PORT)) {
return true;
}
if (environmentPropertySource instanceof EnumerablePropertySource) {
return isAutoDetected((EnumerablePropertySource<?>) environmentPropertySource);
}
}
return false;
}
private boolean isAutoDetected(EnumerablePropertySource<?> environmentPropertySource) {
for (String propertyName : environmentPropertySource.getPropertyNames()) {
if (propertyName.endsWith(SERVICE_HOST_SUFFIX)) {
String serviceName = propertyName.substring(0,
propertyName.length() - SERVICE_HOST_SUFFIX.length());
if (environmentPropertySource.getProperty(serviceName + SERVICE_PORT_SUFFIX) != null) {
return true;
}
}
}
return false;
}
},
/**
* Azure App Service platform.
*/
AZURE_APP_SERVICE {
private final List<String> azureEnvVariables = Arrays.asList("WEBSITE_SITE_NAME", "WEBSITE_INSTANCE_ID",
"WEBSITE_RESOURCE_GROUP", "WEBSITE_SKU");
@Override
public boolean isDetected(Environment environment) {
return this.azureEnvVariables.stream().allMatch(environment::containsProperty);
}
};
private static final String PROPERTY_NAME = "spring.main.cloud-platform";
/**
* Determines if the platform is active (i.e. the application is running in it).
* @param environment the environment
* @return if the platform is active.
*/
public boolean isActive(Environment environment) {
String platformProperty = environment.getProperty(PROPERTY_NAME);
return isEnforced(platformProperty) || (platformProperty == null && isDetected(environment));
}