RestTemplate调用服务接口+@LoadBalanced实现本地负载均衡
1.服务消费者OrderService搭建
- pom依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lchtest</groupId>
<artifactId>springcloud2.0-order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- eureka客户端整合-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
- yaml配置文件
# 订单服务端口号
server:
port: 8001
# 服务别名--服务注册到注册中心的名称
spring:
application:
name: order
eureka:
client:
service-url:
#将当前服务注册到eureka注册中心
defaultZone: http://localhost:8100/eureka/
#将自己注册到注册中心,设置为true
register-with-eureka: true
#需要检索服务信息
fetch-registry: true
- 主启动类
@EnableEurekaClient 注解的作用是将当前服务作为eureka客户端注册到eureka注册中心
package com.lchtest.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
//@EnableEurekaClient 将当前服务注册到eureka注册中心
@EnableEurekaClient
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class, args);
}
// 将RestTemplate交给spring容器管理,controller中注入并使用
@Bean
// 如果使用rest方式以别名方式调用服务提供者的接口,需要依赖ribbon负载均衡器,@LoadBalanced注解启用ribbon负载均衡
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
- OrderController:通过RestTemplate使用rest方式调用服务
package com.lchtest.springcloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
/**
* 订单服务-member服务的消费者
*/
@Controller
@RequestMapping("/order")
public class OrderController {
/**
* 1. springcloud服务调用有两种方式:restTemplate 和Fegin
* 2. resttemplate是由springboot-web组件提供的,默认整合了ribbon负载均衡器,
* spring-cloud-starter-netflix-eureka-client的依赖jar包可以说明,并且底层依赖的是httpclient(依赖了httpclient jar)
*/
@Autowired
private RestTemplate restTemplate;
@RequestMapping("getorder")
@ResponseBody
public String getOrder() {
// String url = "http://127.0.0.1:8000/getmember";
// 使用别名去注册中心获取对应服务调用地址 如果报错java.net.UnknownHostException: member,在restTemplate定义的地方加上@LoadBalanced
String url = "http://app-member/getmember";
String result = restTemplate.getForObject(url, String.class);
System.out.println("订单服务调用会员服务:" + result);
return "订单服务调用会员服务结果:" + result;
}
}
- 服务调用测试
分别启动eureka注册中心,服务提供者member和服务消费者order项目,然后通过http://127.0.0.1:8001/order/getorder去调用member服务:
去掉@LoadBalanced注解注解:
2020-02-16 18:02:24.467 ERROR 2440 --- [nio-8001-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://app-member/getmember": app-member; nested exception is java.net.UnknownHostException: app-member] with root cause
java.net.UnknownHostException: app-member
at java.net.AbstractPlainSocketImpl.connect(Unknown Source) ~[na:1.8.0_181]
说明:
1.springcloud服务调用有两种方式:restTemplate方式调用和Fegin客户端调用;restTemplate是由springboot-web组件提供的,默认整合了ribbon负载均衡器,通过spring-cloud-starter-netflix-eureka-client组件的依赖关系就可以看出来
- restTemplate.getForObject(url, String.class); 方法的使用,url可以有两种写法:http://127.0.0.1:8000/getmember 或者http://app-member/getmember
其中,第二种方式是通过http://服务在注册中心的别名/接口名称 去调用的,这种方式去调用,必须要在定义restTemplate的地方加上@LoadBalanced注解,该注解的作用是开启本地负载均衡,它在开启负载均衡的同时,可以以服务的别名去调用其他服务的接口,如果不加@LoadBalanced注解,直接通过http://app-member/getmember方式调用接口的话,会抛出java.net.UnknownHostException: app-member的异常
3.@LoadBalanced注解会启用ribbon负载均衡,测试如下:
修改member服务的端口号,再启动一个member服务的实例,刷新注册中心服务列表,可以看到app-member有两个实例了,eurekaclient和注册中心的关系如下:
此时再通过order服务调用member 服务的接口,可以看到负载均衡效果了。
需要注意的是,ribbon的负载均衡是客户端本地负载均衡,也就是这里的负载均衡是由order服务依赖的ribbon来完成的
代码地址:
https://github.com/liuch0228/springcloud2.0/tree/master/springcloud2.0-member
https://github.com/liuch0228/springcloud2.0/tree/master/springcloud2.0-order
https://github.com/liuch0228/springcloud2.0/tree/master/springcloud2.0-eureak-server