学习
Spring Cloud
之路,文中Spring Boot
版本为2.1.3.RELEASE
,Spring Cloud
版本为Greenwich.SR1
。因能力有限,难免会有不足或者错误之处,还望不吝指正,谢!
接上篇 Spring Cloud 学习 | - 02 - Eureka集群实现高可用,我们把服务提供者注入到Eureka注册中心,注册完了,我们最终是要消费服务的。本篇将开始进行服务消费的过程。
主要的依赖如下:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
新增接口 UserService
,并添加一个方法 findAll()
:
UserService.java
:
public interface UserService {
/**
* 查询所有用户
* @return
*/
List findAll();
}
并实现该接口 UserServiceImpl
。我们要使用 Spring
的自动注入功能,加上 @Service
注解:
UserServiceImpl.java
:
@Service
public class UserServiceImpl implements UserService {
/**
* 查询所有用户
* @return
*/
@Override
public List findAll() {
List list = Arrays.asList("Cindy","Pony","Marry");
return list;
}
}
新增 UserController
,对外暴露一个 list
接口。
UserController.java
:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/list")
public List list(){
return userService.findAll();
}
}
@RestController
表示这是一个Rest风格的接口,返回的是JSON
,这个注解等效于@Controller
+@ResponseBody
;
server:
port: 8090
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
prefer-ip-address: true # 返回ip而不是host名称
# ip-address: 127.0.0.1 # 指定自己的ip信息
lease-expiration-duration-in-seconds: 15 # 服务失效时间,默认值90秒
lease-renewal-interval-in-seconds: 5 # 服务续约(renew)的间隔,默认为30秒
spring:
application:
name: user-provider
@SpringBootApplication
@EnableDiscoveryClient
public class UserProviderApplication {
public static void main(String[] args) {
SpringApplication.run(UserProviderApplication.class, args);
}
}
依次启动Eureka
服务和user-provider
,访问http://localhost:8761/
:
我们测试一下接口是否正常:
接口正常取到数据。
至此,服务提供者成功注册到eureka注册中心。接下来,开始服务消费者。
利用Spring Initializr
快速创建一个Spring Boot
项目,名称为:user-consumer
,主要依赖如下:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
编写application.yml
配置文件,将服务注册到eureka
注册中心,完整的.yml
配置如下:
server:
port: 8080
spring:
application:
name: user-consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
prefer-ip-address: true
在XxxApplication启动类上添加@EnableDiscoveryClient
启用客户端发现功能,并向IoC容器中注入一个Bean:RestTemplate
,Rest API调用需要用到。
@SpringBootApplication
@EnableDiscoveryClient
public class UserConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(UserConsumerApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@RestController
public class UserController {
@Autowired(required = false)
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/list")
public Object findAll(){
List<ServiceInstance> instanceList = discoveryClient.getInstances("user-provider");
// 我们这里用第一个实例
ServiceInstance instance = instanceList.get(0);
StringBuffer buffer = new StringBuffer("http://");
buffer.append(instance.getHost()).append(":").append(instance.getPort()).append("/user/list");
return restTemplate.getForObject(buffer.toString(), Object.class);
}
}
我们启动user-consumer
服务,查看eureka
注册中心,已经有了user-consumer
服务:
我们测试一下接口是否正常:
成功拿到结果。
这里我们用的是实例列表里取第一个实例,如果是要实现负载均衡,应该是顺序选择或者随机一个实例或者其它什么的。其实我们修改取到实例的方法即可。但是我们是快速开发,不是造轮子,SpringCloud已经帮我们弄好了解决方法,Rest + Ribbon 实现注解式的负载均衡。下边,我们用Rest + Ribbon的方式实现负载均衡的功能。
UserController.java
的list()
方法,返回参数多一个port端口:@GetMapping("/list")
public Map list(){
Map<String,Object> data = new HashMap<>(16);
data.put("port", port);
data.put("rows", userService.findAll());
return data;
}
server:
port: 8091
RestTemplate
这个Bean上加注解@LoadBalanced
,完整的代码如下:@SpringBootApplication
@EnableDiscoveryClient
public class UserConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(UserConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
UserController
,调用方式采用Rest+Ribbon的方式,完整的代码如下:@RestController
public class UserController {
@Autowired(required = false)
private RestTemplate restTemplate;
@GetMapping("/list")
public Object findAll(){
// List instanceList = discoveryClient.getInstances("user-provider");
// // 我们这里用第一个实例
// ServiceInstance instance = instanceList.get(0);
// StringBuffer buffer = new StringBuffer("http://");
// buffer.append(instance.getHost()).append(":").append(instance.getPort()).append("/user/list");
StringBuffer buffer = new StringBuffer("http://").append("user-provider").append("/user/list");
return restTemplate.getForObject(buffer.toString(), Object.class);
}
}
启动user-consumer
进行API接口测试:
结果是对的,并且我们发现返回的数据里port交替出现。已经作了负载均衡,之所以交替出现,是因为默认的负载均衡策略规则是轮询策略,就是一个一个按顺序来。