Check if class is registered already.

In ConfigData promotion (promoting a bean from bootstrap to the application context) check to see if there is a bean of that name before registering again.

Fixes gh-687
This commit is contained in:
spencergibb
2020-12-14 13:12:51 -05:00
parent 16dc8c3c91
commit 418ee24088
13 changed files with 345 additions and 14 deletions

View File

@@ -45,7 +45,7 @@
<module>spring-cloud-consul-config</module>
<module>spring-cloud-consul-discovery</module>
<module>spring-cloud-consul-binder</module>
<module>spring-cloud-consul-sample</module>
<module>spring-cloud-consul-integration-tests</module>
<module>spring-cloud-starter-consul</module>
<module>spring-cloud-starter-consul-bus</module>
<module>spring-cloud-starter-consul-config</module>

View File

@@ -38,6 +38,7 @@ import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.consul.ConsulAutoConfiguration;
import org.springframework.cloud.consul.ConsulProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -153,8 +154,11 @@ public class ConsulConfigDataLocationResolver implements ConfigDataLocationResol
registerBean(context, type, supplier);
context.getBootstrapContext().addCloseListener(event -> {
T instance = event.getBootstrapContext().get(type);
event.getApplicationContext().getBeanFactory().registerSingleton("configData" + type.getSimpleName(),
instance);
String name = "configData" + type.getSimpleName();
ConfigurableApplicationContext appCtxt = event.getApplicationContext();
if (!appCtxt.containsBean(name)) {
appCtxt.getBeanFactory().registerSingleton(name, instance);
}
});
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>spring-cloud-consul-integration-tests</artifactId>
<name>spring-cloud-consul-integration-tests</name>
<description>spring-cloud-consul-integration-tests</description>
<packaging>pom</packaging>
<modules>
<module>spring-cloud-consul-bootstrap-tests</module>
<module>spring-cloud-consul-configdata-tests</module>
</modules>
</project>

View File

@@ -4,14 +4,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-consul-sample</artifactId>
<artifactId>spring-cloud-consul-bootstrap-tests</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Consul Sample</name>
<description>Spring Cloud Consul Sample</description>
<name>Spring Cloud Consul Bootstrap Integration Tests</name>
<description>Spring Cloud Consul Bootstrap Integration Tests</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul</artifactId>
<artifactId>spring-cloud-consul-integration-tests</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
@@ -44,6 +44,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.consul.sample;
package org.springframework.cloud.consul.bootstraptests;
import java.util.List;
@@ -50,10 +50,7 @@ import org.springframework.web.client.RestTemplate;
@EnableConfigurationProperties
@EnableFeignClients
@Slf4j
public class SampleConsulApplication /*
* implements
* ApplicationListener<SimpleRemoteEvent>
*/ {
public class ConsulBootstrapApplication {
@Autowired
private LoadBalancerClient loadBalancer;
@@ -77,7 +74,7 @@ public class SampleConsulApplication /*
private String appName;
public static void main(String[] args) {
SpringApplication.run(SampleConsulApplication.class, args);
SpringApplication.run(ConsulBootstrapApplication.class, args);
}
@RequestMapping("/me")

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.consul.sample;
package org.springframework.cloud.consul.bootstraptests;
import lombok.Data;

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-consul-configdata-tests</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Consul ConfigData Integration Tests</name>
<description>Spring Cloud Consul ConfigData Integration Tests</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul-integration-tests</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!--skip deploy -->
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- Only needed at compile time -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2013-2020 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.cloud.consul.configdatatests;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author Spencer Gibb
*/
@SpringBootApplication
@RestController
@EnableConfigurationProperties
@Slf4j
public class ConsulConfigDataApplication {
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private Environment env;
@Autowired
private RestTemplate restTemplate;
@Autowired
private Registration registration;
@Value("${spring.application.name:testConsulApp}")
private String appName;
public static void main(String[] args) {
SpringApplication.run(ConsulConfigDataApplication.class, args);
}
@RequestMapping("/me")
public ServiceInstance me() {
return this.registration;
}
@RequestMapping("/")
public ServiceInstance lb() {
return this.loadBalancer.choose(this.appName);
}
@RequestMapping("/rest")
public String rest() {
return this.restTemplate.getForObject("http://" + this.appName + "/me", String.class);
}
@RequestMapping("/choose")
public String choose() {
return this.loadBalancer.choose(this.appName).getUri().toString();
}
@RequestMapping("/myenv")
public String env(@RequestParam("prop") String prop) {
return this.env.getProperty(prop, "Not Found");
}
@RequestMapping("/prop")
public String prop() {
return sampleProperties().getProp();
}
@RequestMapping("/instances")
public List<ServiceInstance> instances() {
return this.discoveryClient.getInstances(this.appName);
}
@Bean
public SampleProperties sampleProperties() {
return new SampleProperties();
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2013-2019 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.cloud.consul.configdatatests;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Spencer Gibb
*/
@ConfigurationProperties("sample")
@Data
public class SampleProperties {
private String prop = "default value";
}

View File

@@ -0,0 +1,12 @@
server:
port: 0
spring:
application:
name: testConsulConfigDataIntegrationTestApp
config:
import: 'optional:consul:'
logging:
level:
org.springframework.cloud.consul: DEBUG

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2013-2020 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.cloud.consul.configdatatests;
import java.util.UUID;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.consul.test.ConsulTestcontainers;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.annotation.DirtiesContext;
@DirtiesContext
public class ConsulConfigDataApplicationTests {
private static final String APP_NAME = "testConsulConfigDataIntegration";
private static final String PREFIX = "_configDataIntegrationTests_config__";
private static final String ROOT = PREFIX + UUID.randomUUID();
private static ConfigurableApplicationContext context;
@BeforeAll
public static void setup() {
ConsulTestcontainers.start();
SpringApplication application = new SpringApplication(ConsulConfigDataApplication.class);
context = application.run("--spring.application.name=" + APP_NAME,
"--spring.config.import=consul:" + ConsulTestcontainers.getHost() + ":"
+ ConsulTestcontainers.getPort(),
"--spring.cloud.consul.config.prefix=" + ROOT, "--spring.cloud.consul.config.watch.delay=10");
}
@AfterAll
public static void teardown() {
if (context != null) {
context.close();
}
}
@Test
public void contextLoads() {
}
}