diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java index 3bb72451..5612b575 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java @@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry; import org.springframework.context.ApplicationEventPublisher; import org.springframework.util.ReflectionUtils; diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java index 1f9d38b7..6e084501 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java @@ -40,8 +40,12 @@ import org.springframework.cloud.client.CommonsClientAutoConfiguration; import org.springframework.cloud.client.actuator.HasFeatures; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.context.scope.refresh.RefreshScope; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -70,6 +74,7 @@ import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceI @Configuration @EnableConfigurationProperties @ConditionalOnClass(EurekaClientConfig.class) +@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class) @ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) @AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class }) @@ -149,6 +154,8 @@ public class EurekaClientAutoConfiguration { } @Bean + @ConditionalOnBean(AutoServiceRegistrationProperties.class) + @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager) { return EurekaRegistration.builder(instanceConfig) .with(applicationInfoManager) @@ -157,6 +164,13 @@ public class EurekaClientAutoConfiguration { .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); + } + @Bean @ConditionalOnMissingBean(value = DiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT) public MutableDiscoveryClientOptionalArgs discoveryClientOptionalArgs() { diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java index 7a8e795e..37c938ab 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java @@ -16,9 +16,6 @@ package org.springframework.cloud.netflix.eureka; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.health.HealthAggregator; @@ -26,17 +23,12 @@ import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent; -import org.springframework.context.ApplicationContext; -import org.springframework.context.SmartLifecycle; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.EventListener; -import org.springframework.core.Ordered; import com.netflix.appinfo.EurekaInstanceConfig; import com.netflix.appinfo.HealthCheckHandler; @@ -56,104 +48,32 @@ import lombok.extern.apachecommons.CommonsLog; @ConditionalOnClass(EurekaClientConfig.class) @ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) @CommonsLog -public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Ordered { +public class EurekaDiscoveryClientConfiguration { - private AtomicBoolean running = new AtomicBoolean(false); + class Marker {} - private int order = 0; - - private AtomicInteger port = new AtomicInteger(0); - - @Autowired - private ApplicationContext context; - - @Autowired - private EurekaServiceRegistry serviceRegistry; - - @Autowired - private EurekaRegistration registration; - - @Override - public void start() { - // only set the port if the nonSecurePort is 0 and this.port != 0 - if (this.port.get() != 0 && this.registration.getNonSecurePort() == 0) { - this.registration.setNonSecurePort(this.port.get()); - } - - // only initialize if nonSecurePort is greater than 0 and it isn't already running - // because of containerPortInitializer below - if (!this.running.get() && this.registration.getNonSecurePort() > 0) { - - this.serviceRegistry.register(this.registration); - - this.context.publishEvent( - new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig())); - this.running.set(true); - } - } - @Override - public void stop() { - this.serviceRegistry.deregister(this.registration); - this.running.set(false); - } - - @Override - public boolean isRunning() { - return this.running.get(); - } - - @Override - public int getPhase() { - return 0; - } - - @Override - public boolean isAutoStartup() { - return true; - } - - @Override - public void stop(Runnable callback) { - stop(); - callback.run(); - } - - @Override - public int getOrder() { - return this.order; - } - - @EventListener(EmbeddedServletContainerInitializedEvent.class) - public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) { - // TODO: take SSL into account when Spring Boot 1.2 is available - int localPort = event.getEmbeddedServletContainer().getPort(); - if (this.port.get() == 0) { - log.info("Updating port to " + localPort); - this.port.compareAndSet(0, localPort); - start(); - } + @Bean + public Marker eurekaDiscoverClientMarker() { + return new Marker(); } @Configuration @ConditionalOnClass(RefreshScopeRefreshedEvent.class) protected static class EurekaClientConfigurationRefresher { - @Autowired - private EurekaDiscoveryClientConfiguration clientConfig; + + @Autowired(required = false) + private EurekaAutoServiceRegistration autoRegistration; @EventListener(RefreshScopeRefreshedEvent.class) public void onApplicationEvent(RefreshScopeRefreshedEvent event) { - // register in case meta data changed - this.clientConfig.stop(); - this.clientConfig.start(); + if (autoRegistration != null) { + // register in case meta data changed + this.autoRegistration.stop(); + this.autoRegistration.start(); + } } } - @EventListener(ContextClosedEvent.class) - public void onApplicationEvent(ContextClosedEvent event) { - // register in case meta data changed - stop(); - } - @Configuration @ConditionalOnClass(Endpoint.class) protected static class EurekaHealthIndicatorConfiguration { diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaAutoServiceRegistration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaAutoServiceRegistration.java new file mode 100644 index 00000000..96c10033 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaAutoServiceRegistration.java @@ -0,0 +1,129 @@ +/* + * Copyright 2013-2016 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.cloud.netflix.eureka.serviceregistry; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent; +import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.SmartLifecycle; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.Ordered; + +/** + * @author Dave Syer + * @author Spencer Gibb + * @author Jon Schneider + * @author Jakub Narloch + */ +public class EurekaAutoServiceRegistration implements AutoServiceRegistration, SmartLifecycle, Ordered { + + private static final Log log = LogFactory.getLog(EurekaAutoServiceRegistration.class); + + private AtomicBoolean running = new AtomicBoolean(false); + + private int order = 0; + + private AtomicInteger port = new AtomicInteger(0); + + private ApplicationContext context; + + private EurekaServiceRegistry serviceRegistry; + + private EurekaRegistration registration; + + public EurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry serviceRegistry, EurekaRegistration registration) { + this.context = context; + this.serviceRegistry = serviceRegistry; + this.registration = registration; + } + + @Override + public void start() { + // only set the port if the nonSecurePort is 0 and this.port != 0 + if (this.port.get() != 0 && this.registration.getNonSecurePort() == 0) { + this.registration.setNonSecurePort(this.port.get()); + } + + // only initialize if nonSecurePort is greater than 0 and it isn't already running + // because of containerPortInitializer below + if (!this.running.get() && this.registration.getNonSecurePort() > 0) { + + this.serviceRegistry.register(this.registration); + + this.context.publishEvent( + new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig())); + this.running.set(true); + } + } + @Override + public void stop() { + this.serviceRegistry.deregister(this.registration); + this.running.set(false); + } + + @Override + public boolean isRunning() { + return this.running.get(); + } + + @Override + public int getPhase() { + return 0; + } + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void stop(Runnable callback) { + stop(); + callback.run(); + } + + @Override + public int getOrder() { + return this.order; + } + + @EventListener(EmbeddedServletContainerInitializedEvent.class) + public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) { + // TODO: take SSL into account when Spring Boot 1.2 is available + int localPort = event.getEmbeddedServletContainer().getPort(); + if (this.port.get() == 0) { + log.info("Updating port to " + localPort); + this.port.compareAndSet(0, localPort); + start(); + } + } + + @EventListener(ContextClosedEvent.class) + public void onApplicationEvent(ContextClosedEvent event) { + // register in case meta data changed + stop(); + } + +} diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaRegistration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaRegistration.java similarity index 95% rename from spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaRegistration.java rename to spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaRegistration.java index 11a3f7d4..6bb26ccd 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaRegistration.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaRegistration.java @@ -15,7 +15,7 @@ * */ -package org.springframework.cloud.netflix.eureka; +package org.springframework.cloud.netflix.eureka.serviceregistry; import java.util.concurrent.atomic.AtomicReference; @@ -24,6 +24,9 @@ import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.netflix.eureka.CloudEurekaClient; +import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig; +import org.springframework.cloud.netflix.eureka.InstanceInfoFactory; import org.springframework.context.ApplicationEventPublisher; import org.springframework.util.Assert; diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaServiceRegistry.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaServiceRegistry.java similarity index 94% rename from spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaServiceRegistry.java rename to spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaServiceRegistry.java index 8e72d655..39cb90a0 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaServiceRegistry.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaServiceRegistry.java @@ -15,13 +15,12 @@ * */ -package org.springframework.cloud.netflix.eureka; +package org.springframework.cloud.netflix.eureka.serviceregistry; import java.util.HashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import com.netflix.appinfo.InstanceInfo; @@ -29,7 +28,7 @@ import com.netflix.appinfo.InstanceInfo; /** * @author Spencer Gibb */ -public class EurekaServiceRegistry implements ServiceRegistry, AutoServiceRegistration { +public class EurekaServiceRegistry implements ServiceRegistry { private static final Log log = LogFactory.getLog(EurekaServiceRegistry.class); diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java index 66cdd83f..68bcd48a 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java @@ -52,7 +52,7 @@ public class EurekaClientAutoConfigurationTests { } private void setupContext(Class... config) { - this.context.register(PropertyPlaceholderAutoConfiguration.class); + this.context.register(PropertyPlaceholderAutoConfiguration.class, EurekaDiscoveryClientConfiguration.class); for (Class value : config) { this.context.register(value); } diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java index bf6e3041..c0bf3e3b 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java @@ -28,6 +28,7 @@ import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration; import org.springframework.cloud.netflix.eureka.CloudEurekaClient; import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; +import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -81,6 +82,7 @@ public class DiscoveryClientConfigServiceAutoConfigurationTests { AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(parent, env); parent.register(UtilAutoConfiguration.class, + EurekaDiscoveryClientConfiguration.class, PropertyPlaceholderAutoConfiguration.class, EnvironmentKnobbler.class, EurekaDiscoveryClientConfigServiceBootstrapConfiguration.class, DiscoveryClientConfigServiceBootstrapConfiguration.class, diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/EurekaSampleApplication.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/EurekaSampleApplication.java index 21567e2b..07d039bc 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/EurekaSampleApplication.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/EurekaSampleApplication.java @@ -16,42 +16,39 @@ package org.springframework.cloud.netflix.eureka.sample; +import java.io.Closeable; +import java.io.IOException; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.commons.util.InetUtils; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean; import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean; -import org.springframework.cloud.netflix.eureka.EurekaRegistration; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.EventListener; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.netflix.appinfo.HealthCheckHandler; import com.netflix.appinfo.InstanceInfo; -import java.io.Closeable; -import java.io.IOException; - import static org.springframework.web.bind.annotation.RequestMethod.POST; @Configuration @ComponentScan @EnableAutoConfiguration @RestController -@EnableEurekaClient +@EnableDiscoveryClient public class EurekaSampleApplication implements ApplicationContextAware, Closeable { @Autowired diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientPreprocessorIntegrationTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientPreprocessorIntegrationTests.java index c75f8966..b91d09c1 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientPreprocessorIntegrationTests.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientPreprocessorIntegrationTests.java @@ -24,6 +24,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.commons.util.UtilAutoConfiguration; import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; +import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration; import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.ServerIntrospector; @@ -80,7 +81,8 @@ public class EurekaRibbonClientPreprocessorIntegrationTests { @RibbonClient("foo") @Import({ UtilAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class, - EurekaClientAutoConfiguration.class, RibbonEurekaAutoConfiguration.class }) + EurekaDiscoveryClientConfiguration.class, EurekaClientAutoConfiguration.class, + RibbonEurekaAutoConfiguration.class }) protected static class TestConfiguration { }