Je travaille sur l'application cliente Spring Boot Eureka avec Ribbon Load Balancer.
J'ai deux instances du serveur enregistrées avec Eureka avec le nom "TEST". Côté client, j'ai le code suivant pour récupérer le serveur depuis Eureka.
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableEurekaClient
@RestController
public class EurekaConsumerApplication {
@Autowired
DiscoveryClient discoveryClient;
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/",method = RequestMethod.GET)
String consumer(){
InstanceInfo instance = discoveryClient.getNextServerFromEureka("TEST", false);
URI uri = UriComponentsBuilder.fromUriString(instance.getHomePageUrl() + "baseDir")
.build()
.toUri();
String baseDir = restTemplate.getForObject(uri, String.class);
return baseDir;
}
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
application.yml
spring:
application:
name: consumer
info:
component: Consumer to fetch configuration
server:
port: 8090
eureka:
instance:
leaseRenewalIntervalInSeconds: 3
metadataMap:
instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${random.value}}}
client:
# Default values comes from org.springframework.cloud.netflix.eurek.EurekaClientConfigBean
region: default
registryFetchIntervalSeconds: 5
instanceInfoReplicationIntervalSeconds: 5
initialInstanceInfoReplicationIntervalSeconds: 5
serviceUrl:
defaultZone: http://localhost:8761/eureka/
availabilityZones:
default: ${APPLICATION_DOMAIN:${DOMAIN:defaultZone}}
Cependant, lorsque j'atteins le point de terminaison reposant à l'aide de la commande suivante, cela donne une erreur:
curl http://localhost:8090/
Voici l'erreur:
{"exception":"Java.lang.IllegalStateException","message":"org.springframework.web.util.NestedServletException: Request processing failed; nested exception is Java.lang.IllegalStateException: No instances available for Samarths-MacBook-Pro.local","path":"/"}
Trace de la pile:
2015-07-22 14:37:35.005 INFO 13841 --- [tp1334391583-19] c.netflix.loadbalancer.BaseLoadBalancer : Client:Samarths-MacBook-Pro.local instantiated a LoadBalancer:DynamicServerListLoadBalancer:{NFLoadBalancer:name=Samarths-MacBook-Pro.local,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2015-07-22 14:37:35.009 INFO 13841 --- [tp1334391583-19] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client Samarths-MacBook-Pro.local initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=Samarths-MacBook-Pro.local,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@681eda37
2015-07-22 14:37:35.029 WARN 13841 --- [tp1334391583-19] o.Eclipse.jetty.servlet.ServletHandler :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is Java.lang.IllegalStateException: No instances available for Samarths-MacBook-Pro.local
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:978)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.Java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:687)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.Java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:790)
at org.Eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.Java:808)
at org.Eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1669)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.Java:295)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107)
at org.Eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1652)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.Java:102)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107)
at org.Eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1652)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.Java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107)
at org.Eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1652)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.Java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107)
at org.Eclipse.jetty..ServletHandler$CachedChain.doFilter(ServletHandler.Java:1652)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.Java:68)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107)
at org.Eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1652)
at org.Eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.Java:585)
at org.Eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.Java:143)
at org.Eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.Java:548)
at org.Eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.Java:223)
at org.Eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.Java:1127)
at org.Eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.Java:515)
at org.Eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.Java:185)
at org.Eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.Java:1061)
at org.Eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.Java:141)
at org.Eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.Java:97)
at org.Eclipse.jetty.server.Server.handle(Server.Java:499)
at org.Eclipse.jetty.server.HttpChannel.handle(HttpChannel.Java:310)
at org.Eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.Java:257)
at org.Eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.Java:540)
at org.Eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.Java:635)
at org.Eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.Java:555)
at Java.lang.Thread.run(Thread.Java:745)
Caused by: Java.lang.IllegalStateException: No instances available for Samarths-MacBook-Pro.local
at org.springframework.cloud.netflix.ribbon.RibbonClientHttpRequestFactory.createRequest(RibbonClientHttpRequestFactory.Java:64)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.Java:76)
at org.springframework.web.client.Rlate.doExecute(RestTemplate.Java:565)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.Java:545)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.Java:253)
at com.securityscorecard.eureka.consumer.EurekaConsumerApplication.consumer(EurekaConsumerApplication.Java:53)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.Java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.Java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.Java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.Java:776)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.Java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.Java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.Java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.Java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:966)
... 38 common frames omitted
On dirait que ma liste de serveurs est vide.
Le RestTemplate
que vous avez câblé automatiquement est déjà connecté au ruban. Vous effectuez donc une recherche à la main, puis RestTemplate
essaie de rechercher le nom d'hôte transmis au ruban. Vous avez deux options: 1) N'utilisez pas le netflix DiscoveryClient
et passez le serviceId en tant que nom d'hôte logique au ruban (http://TEST/myservice
), 2) N'utilisez pas le RestTemplate
autowired, créez-en un nouveau pour votre classe. Mon choix serait le n ° 1.
Je l'ai fait fonctionner. Le seul changement que j'ai dû faire était dans la façon dont j'utilisais l'API RestTemplate.
Code d'erreur:
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/",method = RequestMethod.GET)
String consumer(){
String baseDir = restTemplate.getForObject("TEST", String.class);
return baseDir;
}
Code de travail:
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/",method = RequestMethod.GET)
String consumer(){
String baseDir = restTemplate.getForObject("http://TEST", String.class);
return baseDir;
}
Solution:
Le premier paramètre de restTemplate.getForObject doit avoir le format d'une URL. Et le nom de domaine doit être le nom du service que vous souhaitez découvrir.
Ex: http: // TEST . Ici, TEST est le nom de mon serveur enregistré dans le registre eureka
La question est déjà répondue, mais j'ai trouvé une solution de contournement qui semble soignée et a résolu notre problème.
Déclarez d'abord une nouvelle classe @Component et créez-y une méthode qui renvoie RestTemplate:
@Component
public class RestTemplateComponentFix{
@Autowired
SomeConfigurationYouNeed someConfiguration;
@LoadBalanced
public RestTemplate getRestTemplate() {
// TODO set up your restTemplate
rt.setRequestFactory( new HttpComponentsClientHttpRequestFactory() );
return rt;
}
}
Après cela, il suffit de câbler automatiquement le restTemplateComponentFix dans votre classe et lorsque vous avez besoin du modèle de repos, appelez la méthode restTemplate (). Quelque chose comme ça:
@Service
public class someClass{
@Autowired
RestTemplateComponentFix restTemplateComponentFix;
public void methodUsingRestTemplate(){
// Some code...
RestTemplate rt = restTemplateComponentFix.getRestTemplate();
// Some code...
}
}
Après cela, vous pouvez tester l'unité avec quelque chose comme:
RestTemplate rt = Mockito.mock(RestTemplate.class)
when(restTemplateComponentFix.getRestTemplate()).thenReturn(rt);
when(rt.someMethod()).thenReturn(something);