Commit c181163a by Taras Danylchuk Committed by Ryan Baxter

fixes https://github.com/spring-cloud/spring-cloud-netflix/issues/2972 (#3018)

root cause: cached bean trying to re-register resolution summary: get re-created bean from context to re-register
parent 8af3ae8a
...@@ -26,6 +26,7 @@ import java.lang.annotation.Target; ...@@ -26,6 +26,7 @@ import java.lang.annotation.Target;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.Map; import java.util.Map;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
...@@ -94,9 +95,6 @@ import com.netflix.discovery.EurekaClientConfig; ...@@ -94,9 +95,6 @@ import com.netflix.discovery.EurekaClientConfig;
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"}) "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"})
public class EurekaClientAutoConfiguration { public class EurekaClientAutoConfiguration {
@Autowired(required = false)
private HealthCheckHandler healthCheckHandler;
@Bean @Bean
public HasFeatures eurekaFeature() { public HasFeatures eurekaFeature() {
return HasFeatures.namedFeature("Eureka Client", EurekaClient.class); return HasFeatures.namedFeature("Eureka Client", EurekaClient.class);
...@@ -203,18 +201,8 @@ public class EurekaClientAutoConfiguration { ...@@ -203,18 +201,8 @@ public class EurekaClientAutoConfiguration {
@Bean @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager) { public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry,
return EurekaRegistration.builder(instanceConfig) EurekaRegistration registration) {
.with(applicationInfoManager)
.with(eurekaClient)
.with(healthCheckHandler)
.build();
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) {
return new EurekaAutoServiceRegistration(context, registry, registration); return new EurekaAutoServiceRegistration(context, registry, registration);
} }
...@@ -242,6 +230,20 @@ public class EurekaClientAutoConfiguration { ...@@ -242,6 +230,20 @@ public class EurekaClientAutoConfiguration {
InstanceInfo instanceInfo = new InstanceInfoFactory().create(config); InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
return new ApplicationInfoManager(config, instanceInfo); return new ApplicationInfoManager(config, instanceInfo);
} }
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
CloudEurekaInstanceConfig instanceConfig,
ApplicationInfoManager applicationInfoManager,
@Autowired(required = false) HealthCheckHandler healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.with(healthCheckHandler)
.build();
}
} }
@Configuration @Configuration
...@@ -273,6 +275,21 @@ public class EurekaClientAutoConfiguration { ...@@ -273,6 +275,21 @@ public class EurekaClientAutoConfiguration {
return new ApplicationInfoManager(config, instanceInfo); return new ApplicationInfoManager(config, instanceInfo);
} }
@Bean
@org.springframework.cloud.context.config.annotation.RefreshScope
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
CloudEurekaInstanceConfig instanceConfig,
ApplicationInfoManager applicationInfoManager,
@Autowired(required = false) HealthCheckHandler healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.with(healthCheckHandler)
.build();
}
} }
@Target({ ElementType.TYPE, ElementType.METHOD }) @Target({ ElementType.TYPE, ElementType.METHOD })
......
...@@ -44,7 +44,7 @@ import com.netflix.discovery.EurekaClientConfig; ...@@ -44,7 +44,7 @@ import com.netflix.discovery.EurekaClientConfig;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
*/ */
public class EurekaRegistration implements Registration, Closeable { public class EurekaRegistration implements Registration {
private static final Log log = LogFactory.getLog(EurekaRegistration.class); private static final Log log = LogFactory.getLog(EurekaRegistration.class);
private final EurekaClient eurekaClient; private final EurekaClient eurekaClient;
...@@ -201,8 +201,4 @@ public class EurekaRegistration implements Registration, Closeable { ...@@ -201,8 +201,4 @@ public class EurekaRegistration implements Registration, Closeable {
return this.instanceConfig.getSecurePort(); return this.instanceConfig.getSecurePort();
} }
@Override
public void close() throws IOException {
this.eurekaClient.shutdown();
}
} }
...@@ -16,27 +16,32 @@ ...@@ -16,27 +16,32 @@
package org.springframework.cloud.netflix.eureka; package org.springframework.cloud.netflix.eureka;
import java.io.IOException;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.aop.framework.Advised;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.commons.util.UtilAutoConfiguration; import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.cloud.context.scope.GenericScope; import org.springframework.cloud.context.scope.GenericScope;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.test.util.ReflectionTestUtils;
import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.discovery.EurekaClient; import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaClientConfig; import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient; import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
...@@ -45,8 +50,6 @@ import com.sun.jersey.client.apache4.ApacheHttpClient4; ...@@ -45,8 +50,6 @@ import com.sun.jersey.client.apache4.ApacheHttpClient4;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.boot.test.util.EnvironmentTestUtils.addEnvironment; import static org.springframework.boot.test.util.EnvironmentTestUtils.addEnvironment;
/** /**
...@@ -367,6 +370,43 @@ public class EurekaClientAutoConfigurationTests { ...@@ -367,6 +370,43 @@ public class EurekaClientAutoConfigurationTests {
} }
@Test @Test
public void shouldReregisterHealthCheckHandlerAfterRefresh() throws Exception {
addEnvironment(this.context, "eureka.client.healthcheck.enabled=true");
setupContext(RefreshAutoConfiguration.class, AutoServiceRegistrationConfiguration.class);
EurekaClient oldEurekaClient = getLazyInitEurekaClient();
HealthCheckHandler healthCheckHandler = this.context.getBean("eurekaHealthCheckHandler", HealthCheckHandler.class);
assertThat(healthCheckHandler).isInstanceOf(EurekaHealthCheckHandler.class);
assertThat(oldEurekaClient.getHealthCheckHandler()).isSameAs(healthCheckHandler);
ContextRefresher refresher = this.context.getBean("contextRefresher", ContextRefresher.class);
refresher.refresh();
EurekaClient newEurekaClient = getLazyInitEurekaClient();
HealthCheckHandler newHealthCheckHandler = this.context.getBean("eurekaHealthCheckHandler", HealthCheckHandler.class);
assertThat(healthCheckHandler).isSameAs(newHealthCheckHandler);
assertThat(oldEurekaClient).isNotSameAs(newEurekaClient);
assertThat(newEurekaClient.getHealthCheckHandler()).isSameAs(healthCheckHandler);
}
@Test
public void shouldCloseDiscoveryClient() throws Exception {
addEnvironment(this.context, "eureka.client.healthcheck.enabled=true");
setupContext(RefreshAutoConfiguration.class, AutoServiceRegistrationConfiguration.class);
AtomicBoolean isShutdown = (AtomicBoolean) ReflectionTestUtils.getField(getLazyInitEurekaClient(), "isShutdown");
assertThat(isShutdown.get()).isFalse();
this.context.close();
assertThat(isShutdown.get()).isTrue();
}
@Test
public void basicAuth() { public void basicAuth() {
addEnvironment(this.context, "server.port=8989", addEnvironment(this.context, "server.port=8989",
"eureka.client.serviceUrl.defaultZone=http://user:foo@example.com:80/eureka"); "eureka.client.serviceUrl.defaultZone=http://user:foo@example.com:80/eureka");
...@@ -425,16 +465,6 @@ public class EurekaClientAutoConfigurationTests { ...@@ -425,16 +465,6 @@ public class EurekaClientAutoConfigurationTests {
} }
} }
@Test
public void eurekaRegistrationClosed() throws IOException {
setupContext(TestEurekaRegistrationConfiguration.class);
if (this.context != null) {
EurekaRegistration registration = this.context.getBean(EurekaRegistration.class);
this.context.close();
verify(registration).close();
}
}
private void testNonSecurePort(String propName) { private void testNonSecurePort(String propName) {
addEnvironment(this.context, propName + ":8888"); addEnvironment(this.context, propName + ":8888");
setupContext(); setupContext();
...@@ -452,6 +482,10 @@ public class EurekaClientAutoConfigurationTests { ...@@ -452,6 +482,10 @@ public class EurekaClientAutoConfigurationTests {
return this.context.getBean(EurekaInstanceConfigBean.class); return this.context.getBean(EurekaInstanceConfigBean.class);
} }
private EurekaClient getLazyInitEurekaClient() throws Exception {
return (EurekaClient)((Advised) this.context.getBean("eurekaClient", EurekaClient.class)).getTargetSource().getTarget();
}
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
@Import({ UtilAutoConfiguration.class, EurekaClientAutoConfiguration.class }) @Import({ UtilAutoConfiguration.class, EurekaClientAutoConfiguration.class })
...@@ -482,18 +516,6 @@ public class EurekaClientAutoConfigurationTests { ...@@ -482,18 +516,6 @@ public class EurekaClientAutoConfigurationTests {
} }
@Configuration @Configuration
protected static class TestEurekaRegistrationConfiguration {
@Bean
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager) {
return spy(EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.build());
}
}
@Configuration
protected static class MockClientConfiguration { protected static class MockClientConfiguration {
@Bean @Bean
...@@ -515,4 +537,10 @@ public class EurekaClientAutoConfigurationTests { ...@@ -515,4 +537,10 @@ public class EurekaClientAutoConfigurationTests {
return Mockito.mock(ApacheHttpClient4.class); return Mockito.mock(ApacheHttpClient4.class);
} }
} }
@Configuration
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
public static class AutoServiceRegistrationConfiguration {
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment