Add RefreshEndpoint
This commit is contained in:
@@ -27,9 +27,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.platform.bootstrap.config.ConfigServiceBootstrapConfiguration;
|
||||
import org.springframework.platform.config.client.RefreshEndpoint;
|
||||
import org.springframework.platform.context.environment.EnvironmentManager;
|
||||
import org.springframework.platform.context.environment.EnvironmentManagerMvcEndpoint;
|
||||
import org.springframework.platform.context.properties.ConfigurationPropertiesRebinder;
|
||||
@@ -66,6 +69,14 @@ public class RefreshAutoConfiguration {
|
||||
return rebinder;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnExpression("${endpoints.refresh.enabled:true}")
|
||||
public RefreshEndpoint refreshEndpoint(ConfigurableApplicationContext context, ConfigServiceBootstrapConfiguration bootstrap) {
|
||||
RefreshEndpoint endpoint = new RefreshEndpoint(context, bootstrap);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnClass(EnvironmentEndpoint.class)
|
||||
|
||||
@@ -106,6 +106,7 @@ public class BootstrapApplicationListener implements
|
||||
context.close();
|
||||
}
|
||||
});
|
||||
application.addInitializers(new AncestorInitializer(context));
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -134,5 +135,23 @@ public class BootstrapApplicationListener implements
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
private static class AncestorInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
private ConfigurableApplicationContext parent;
|
||||
|
||||
public AncestorInitializer(ConfigurableApplicationContext parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext context) {
|
||||
while (context.getParent()!=null) {
|
||||
context = (ConfigurableApplicationContext) context.getParent();
|
||||
}
|
||||
context.setParent(parent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
package org.springframework.platform.bootstrap.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -30,7 +30,10 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.platform.config.client.ConfigServicePropertySourceLocator;
|
||||
import org.springframework.platform.config.client.PropertySourceLocator;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -45,6 +48,11 @@ public class ConfigServiceBootstrapConfiguration implements
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<PropertySourceLocator>();
|
||||
|
||||
public void setPropertySourceLocators(
|
||||
Collection<PropertySourceLocator> propertySourceLocators) {
|
||||
this.propertySourceLocators = new ArrayList<PropertySourceLocator>(propertySourceLocators);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
@@ -66,12 +74,16 @@ public class ConfigServiceBootstrapConfiguration implements
|
||||
empty = false;
|
||||
}
|
||||
if (!empty) {
|
||||
applicationContext.getEnvironment().getPropertySources().addFirst(composite);
|
||||
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
|
||||
if (propertySources.contains("bootstrap")) {
|
||||
propertySources.replace("bootstrap", composite);
|
||||
} else {
|
||||
propertySources.addFirst(composite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("spring.platform.config")
|
||||
public ConfigServicePropertySourceLocator configServicePropertySource() {
|
||||
return new ConfigServicePropertySourceLocator();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.platform.bootstrap.config;
|
||||
package org.springframework.platform.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.platform.bootstrap.config;
|
||||
package org.springframework.platform.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -14,21 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.platform.bootstrap.config;
|
||||
package org.springframework.platform.config.client;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.platform.config.Environment;
|
||||
import org.springframework.platform.config.PropertySource;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@ConfigurationProperties("spring.platform.config")
|
||||
public class ConfigServicePropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
private String env = "development";
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.platform.bootstrap.config;
|
||||
package org.springframework.platform.config.client;
|
||||
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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
|
||||
*
|
||||
* http://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.platform.config.client;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.platform.bootstrap.config.ConfigServiceBootstrapConfiguration;
|
||||
import org.springframework.platform.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "endpoints.refresh", ignoreUnknownFields = false)
|
||||
public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
private ConfigServiceBootstrapConfiguration bootstrap = new ConfigServiceBootstrapConfiguration();
|
||||
|
||||
public RefreshEndpoint(ConfigurableApplicationContext context, ConfigServiceBootstrapConfiguration bootstrap) {
|
||||
super("refresh");
|
||||
this.context = context;
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> invoke() {
|
||||
Map<String, Object> before = extract(context.getEnvironment().getPropertySources());
|
||||
bootstrap.initialize(context);
|
||||
Set<String> keys = changes(before,
|
||||
extract(context.getEnvironment().getPropertySources())).keySet();
|
||||
if (keys.isEmpty()) {
|
||||
return keys;
|
||||
}
|
||||
context.publishEvent(new EnvironmentChangeEvent(keys));
|
||||
return keys;
|
||||
}
|
||||
|
||||
private Map<String, Object> changes(Map<String, Object> before,
|
||||
Map<String, Object> after) {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
for (String key : before.keySet()) {
|
||||
if (!after.containsKey(key)) {
|
||||
result.put(key, null);
|
||||
} else if (!equal(before.get(key), after.get(key))) {
|
||||
result.put(key, after.get(key));
|
||||
}
|
||||
}
|
||||
for (String key : after.keySet()) {
|
||||
if (!before.containsKey(key)) {
|
||||
result.put(key, after.get(key));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean equal(Object one, Object two) {
|
||||
if (one == null && two == null) {
|
||||
return true;
|
||||
}
|
||||
if (one == null || two == null) {
|
||||
return false;
|
||||
}
|
||||
return one.equals(two);
|
||||
}
|
||||
|
||||
private Map<String, Object> extract(MutablePropertySources propertySources) {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
PropertySource<?> parent = propertySources.get("bootstrap");
|
||||
extract(parent, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void extract(PropertySource<?> parent, Map<String, Object> result) {
|
||||
if (parent instanceof CompositePropertySource) {
|
||||
try {
|
||||
Field field = ReflectionUtils.findField(CompositePropertySource.class,
|
||||
"propertySources");
|
||||
field.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<PropertySource<?>> sources = (Set<PropertySource<?>>) field.get(parent);
|
||||
for (PropertySource<?> source : sources) {
|
||||
extract(source, result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
} else if (parent instanceof EnumerablePropertySource) {
|
||||
for (String key : ((EnumerablePropertySource<?>) parent).getPropertyNames()) {
|
||||
result.put(key, parent.getProperty(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.platform.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.platform.config.client.PropertySourceLocator;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
<logger name="org.springframework.boot.env.PropertySourcesLoader" level="TRACE"/>
|
||||
<!-- logger name="org.springframework.security" level="DEBUG"/-->
|
||||
</configuration>
|
||||
@@ -21,14 +21,14 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
@WebAppConfiguration
|
||||
public class ApplicationTests {
|
||||
|
||||
private static int configPort;
|
||||
private static int configPort = 0;
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
@BeforeClass
|
||||
public static void startConfigServer() {
|
||||
ConfigurableApplicationContext context = SpringApplication.run(org.springframework.platform.config.server.Application.class, "--server.port=0");
|
||||
ConfigurableApplicationContext context = SpringApplication.run(org.springframework.platform.config.server.Application.class, "--server.port=" + configPort, "--spring.config.name=server");
|
||||
configPort = ((EmbeddedWebApplicationContext)context).getEmbeddedServletContainer().getPort();
|
||||
System.setProperty("config.port", "" + configPort);
|
||||
}
|
||||
@@ -38,5 +38,17 @@ public class ApplicationTests {
|
||||
String foo = new TestRestTemplate().getForObject("http://localhost:" + port + "/env/foo", String.class);
|
||||
assertEquals("bar", foo);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("spring.jmx.default_domain", "platform.config.server");
|
||||
System.setProperty("endpoints.jmx.domain", "platform.config.server");
|
||||
System.setProperty("spring.platform.config.server.basedir", "target/config");
|
||||
configPort = 8888;
|
||||
startConfigServer();
|
||||
System.clearProperty("spring.jmx.default_domain");
|
||||
System.clearProperty("endpoints.jmx.domain");
|
||||
System.clearProperty("spring.platform.config.server.basedir");
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
info:
|
||||
component: Config Server
|
||||
spring:
|
||||
application:
|
||||
name: configserver
|
||||
server:
|
||||
port: 8888
|
||||
management:
|
||||
contextPath: /admin
|
||||
@@ -10,7 +10,7 @@ import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.config.Environment;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.platform.config.server;
|
||||
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.config.Environment;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,8 +24,8 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.bootstrap.config.PropertySource;
|
||||
import org.springframework.platform.config.Environment;
|
||||
import org.springframework.platform.config.PropertySource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,8 +24,8 @@ import java.util.Set;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.bootstrap.config.PropertySource;
|
||||
import org.springframework.platform.config.Environment;
|
||||
import org.springframework.platform.config.PropertySource;
|
||||
import org.springframework.web.context.support.StandardServletEnvironment;
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.config.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,4 +4,6 @@ spring:
|
||||
application:
|
||||
name: configserver
|
||||
server:
|
||||
port: 8888
|
||||
port: 8888
|
||||
management:
|
||||
context_path: /admin
|
||||
@@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.boot.test.TestRestTemplate;
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.config.Environment;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.io.File;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.config.Environment;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.platform.config.server;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.platform.bootstrap.config.Environment;
|
||||
import org.springframework.platform.config.Environment;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user