美文网首页
SpringCloud @LoadBalanced注解使用报错

SpringCloud @LoadBalanced注解使用报错

作者: 左羊 | 来源:发表于2019-07-23 23:08 被阅读0次

错误描述

我遇到的问题是通过@Autowired注入的restTemplate无法访问IP加端口,new RestTemplate则可以访问?

1.通过注入方式访问连接时报了以下异常。

java.lang.IllegalStateException: No instances available for XXX

image

2.通过new RestTemplate则可以正常访问。

解决方案
首先我在config包中发现如下配置,我发现我在restTemplate模板对象上加@LoadBalanced注解

  @Bean
   @LoadBalanced
   public RestTemplate getRestTemplate(){
       return new RestTemplate();
   }

为什么加上 @LoadBalanced就不能访问ip加端口呢?
主要因为其使用ribbon组件,当我们应用依赖了eureka-client的时候,eureka-client依赖了ribbon,虽然看是ribbon没有存在感,但是ribbon默默的发挥着自己的负载均衡能力。在加了注解 @LoadBalanced 之后,我们的restTemplate 会走这个类RibbonLoadBalancerClient,serverid必须是我们访问的服务名称 ,当我们直接输入ip的时候获取的server是null,就会抛出异常。而这个服务名称是需要我们在Eureka中配置的,如果没有配置直接访问则会报错。
RibbonLoadBalancerClient.java


image

通过Debug断点进入这个方法

image
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
   Server server = null;
   if(serviceInstance instanceof RibbonServer) {
      server = ((RibbonServer)serviceInstance).getServer();
   }
   if (server == null) {
      throw new IllegalStateException("No instances available for " + serviceId);
   }

   RibbonLoadBalancerContext context = this.clientFactory
         .getLoadBalancerContext(serviceId);
   RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

   try {
      T returnVal = request.apply(serviceInstance);
      statsRecorder.recordStats(returnVal);
      return returnVal;
   }
   // catch IOException and rethrow so RestTemplate behaves correctly
   catch (IOException ex) {
      statsRecorder.recordStats(ex);
      throw ex;
   }
   catch (Exception ex) {
      statsRecorder.recordStats(ex);
      ReflectionUtils.rethrowRuntimeException(ex);
   }
   return null;
}

在这里我们就可以发现那个错误信息,因为没有找到相对应的服务,所以server为null,又因为server为null,所以会抛出java.lang.IllegalStateException: No instances available for XXX这个异常信息。

有这么一句谚语说的好,“谁都会骗你,但源码是不会骗你的”。

因为ribbon的作用是负载均衡,那么你直接使用ip地址,那么就无法起到负载均衡的作用,因为每次都是调用同一个服务,当你使用的是服务名称的时候,他会根据自己的算法去选择具有该服务名称的服务。

结论:因为我的IP没有在Eureka中经行配置。
为什么使用new RestTemplate则可以正常访问?
因为添加了ribbon依赖后,会在项目启动的时候自动往RestTemplate中添加LoadBalancerInterceptor拦截器,直接new的对象没有加@LoadBalanced,通过Debug工具发现在访问时没有被该拦截器拦截。所以就能正常访问。

总结

1)用户创建RestTemplate
2)添加了ribbon依赖后,会在项目启动的时候自动往RestTemplate中添加LoadBalancerInterceptor拦截器
3)用户根据RestTemplate发起请求时,会将请求转发到LoadBalancerInterceptor去执行,该拦截器会根据指定的负载均衡方式获取该次请求对应的应用服务端IP、port
4)根据获取到的IP、port重新封装请求,发送HTTP请求,返回具体响应

参考:
SpringCloud微服务实战
https://blog.csdn.net/qq_26323323/article/details/81327669
https://blog.csdn.net/weixin_42107940/article/details/84028403
https://blog.csdn.net/awhip9/article/details/70599014

相关文章

  • SpringCloud @LoadBalanced注解使用报错

    错误描述 我遇到的问题是通过@Autowired注入的restTemplate无法访问IP加端口,new Rest...

  • @LoadBalanced注解

    @LoadBalanced注解在生产环境使用的不太多,主要是springcloud项目,访问下游服务的时候,用服务...

  • Ribbon负载均衡原理

    我们添加了 @LoadBalanced 注解,即可实现负载均衡功能,这是什么原理呢?SpringCloud 底层提...

  • SpringCloud之@LoadBalanced

    SpringCloud是构建在Spring规则之上的代表作。阅读起来很复杂,其中的@LoadBalanced注解堪...

  • 笔记3-SpringCloud Ribbon

    使用 在创建RestTemplate实例时使用@LoadBalanced注解标注。org.springframew...

  • SpringCloud微服务调用的方式

    ribbon模式使用 @LoadBalanced @Bean 注解修饰 RestTemplate使用服务名调用re...

  • Ribbon

    在springcloud中,引入Ribbon来作为客户端时,负载均衡使用的是被@LoadBalanced修饰的Re...

  • Ribbon源码解析

    1.简单使用1.1.在启动类中,声明一个RestTemplate的bean,用@LoadBalanced注解修饰:...

  • SpringCloud源码解析 -- RestTemplate与

    本文主要分享SpringCloud中RestTemplate与@LoadBalanced的实现原理。源码分析基于S...

  • ribbon源码解析

    ribbon的使用非常简单,只需要在spring容器中注入一个带有@LoadBalanced注解的RestTmpl...

网友评论

      本文标题:SpringCloud @LoadBalanced注解使用报错

      本文链接:https://www.haomeiwen.com/subject/yjbzlctx.html