先贴代码:
@RestController public class CallHelloController { @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate;
@RequestMapping("/call") public String call(){ ServiceInstance serviceInstance = loadBalancerClient.choose("service-producer"); System.out.println("服务地址:" + serviceInstance.getUri()); System.out.println("服务名称:" + serviceInstance.getServiceId()); String callServiceResult = restTemplate.getForObject(serviceInstance.getUri().toString() + "/hello", String.class); System.out.println(callServiceResult); return callServiceResult; }
@SpringBootApplication @EnableDiscoveryClient //单纯的消费(不对外提供服务)可以不注册 @RibbonClient(name = "service-producer", configuration = RibbonConfig.class) @ComponentScan(excludeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION, value=ExcludeFromComponentScan.class)} ) public class SpringCloudConsulConsumerApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudConsulConsumerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
application.properties
spring.application.name=spring-cloud-consul-producer server.port=8802 spring.cloud.consul.host=localhost spring.cloud.consul.port=8500 #注册到consul的服务名称 spring.cloud.consul.discovery.serviceName=service-producer
实际上,/call请求映射方法存在问题;
问题是 因为 LoadBalancedClient 这里的 choose 根据 Consul注册的服务名(spring.cloud.consul.discovery.serviceName=service-producer) 命中一个服务提供者;
这里就不能使用加了LoadBalanced注解的RestTemplate对象了,因为会根据 host 去Consul查找服务提供者,这样就会抛异常 :No instances available for XXX ,也就是找不到指定的服务ID
原因:"服务地址:" + serviceInstance.getUri()这儿出现了问题。
即:
LoadBalancerClient进行手动的http请求;Ribbon集成了Apache HttpClient 、 OkHttp请求客户端使用;
我们不使用ribbon的时候,使用serviceInstance.getUri()访问是没问题的。
但是,当我们集成Ribbon后,就不行了。
辅助信息:
打印的信息:
服务地址:http://maq.xxxx.com:8802
服务名称:spring-cloud-consul-producer
serviceInstance对象信息:RibbonServer{serviceId='spring-cloud-consul-producer', server=maq.xxxx.com:8802, secure=false, metadata={secure=false}}
/** * Creates a URI from the given ServiceInstance's host:port. * @param instance the ServiceInstance. * @return URI of the form (secure)?https:http + "host:port". */ public static URI getUri(ServiceInstance instance) { String scheme = (instance.isSecure()) ? "https" : "http"; //http String uri = String.format("%s://%s:%s", scheme, instance.getHost(), //host:maq.xxxx.com instance.getPort()); return URI.create(uri); }
我们访问的:http://maq.xxxx.com:8802
主要原因:LoadBalancerClient进行手动的http请求;Ribbon集成了Apache HttpClient 、 OkHttp请求客户端使用;
解决办法1:
在application.properties文件中加如下配置:
ribbon.okhttp.enabled= true ribbon.restclient.enabled= true
解决办法二:
指定访问的http://serviceId/path (多个服务配置相同的spring.application.name=serviceId)
@RequestMapping("/getPathParam1/{user}") public String getPathParam2(@PathVariable("user") String username){ ServiceInstance serviceInstance = loadBalancerClient.choose("service-producer"); System.out.println("服务地址:" + serviceInstance.getUri()); System.out.println("服务名称:" + serviceInstance.getServiceId()); String paramServiceResult = restTemplate.getForObject("http://" + serviceInstance.getServiceId().toString() + "/hello1/{user}", String.class,username); //String paramServiceResult = restTemplate.getForObject("http://spring-cloud-consul-producer/hello1/{user}", String.class,username); System.out.println(paramServiceResult); return paramServiceResult; }
参考链接:https://www.cnblogs.com/XingXiaoMeng/p/10958644.html