Ribbon + RestTemplate 负载均衡时,解析服务提供者程序名为实际ip,port时抛null 异常

1. 场景

在学习Ribbon + RestTemplate 测试Ribbon的负载均衡功能时,发现RestTemplate 使用服务提供者的服务名去请求Rest接口时,报null 指针异常。

2. 代码结构如下

2.1 服务提供者

(1) application.yml

server:
  port: 7900
spring:
  application:
    name: eureka_producer_user
  jpa:
    generate-ddl: false
    show-sql: true
    hibernate:
      ddl-auto: none
  datasource:
    platform: h2
    schema: classpath:schema.sql
    data: classpath:data.sql
logging:
  level:
    root: info
    org.hibernate: info
    org.hibernate.type.descriptor.sql.BasicBinder: trace
    org.hibernate.type.descriptor.sql.BasicExtractor: trace
    com.example.spring.cloud: debug

eureka:
  client:
    heathcheck:
      enabled: true
    service-url:
      defaultZone: http://user:password123@localhost:8761/eureka
    instance:
        instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}

(2) Application类

@SpringBootApplication
@EnableDiscoveryClient
public class ProducerUserApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProducerUserApplication.class, args);
    }
}

(3) 对外暴露的Controller类 的接口

@RestController
public class UserController {
    @Autowired
    private UserRepository userRepository;

    @GetMapping("/simple/{id}")
    public User findById(@PathVariable(name = "id") Long id) {
        return userRepository.findById(id);
    }
}

2.2 服务消费者

(1) application.yml

server:
  port: 8010
spring:
  application:
    name: eureka_consumer_movie_ribbon

logging:
  level:
    root: info
    com.example.spring.cloud: debug
eureka:
  client:
    heathcheck:
      enabled: true
    service-url:
      defaultZone: http://user:password123@localhost:8761/eureka
    instance:
      instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}

(2) Application类

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerMovieRibbonApplication {

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

    public static void main(String[] args) {
        SpringApplication.run(ConsumerMovieRibbonApplication.class, args);
    }
}

(3) Controller类

@RestController
public class MovieController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/user/{id}")
    public User findById(@PathVariable("id") Long id) {
        // VIP virtual IP
        // HAProxy Heartbeat
        return restTemplate.getForObject("http://eureka_producer_user/simple/" + id, User.class);
    }
}

3. 异常

请求 http://localhost:8010/user/1 时抛出如下异常:

异常

4. 异常排查

通过对异常栈进行debug ,发现是由于URI 类对于http://host:port/path这种结构 中的host 属性,不支持host中含_(下划线),不然解析出来的host就为null, 最终导致抛出NullPointerException。

5. 相关issues

https://github.com/spring-cloud/spring-cloud-netflix/issues/1582
https://github.com/spring-cloud/spring-cloud-netflix/issues/263

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容