提问 : 假如我们的服务提供者user-service部署了多个实例,如图:
我们需要思考几个问题 :
order-service在发起远程调用的时候,该如何得知user-service实例的
ip地址和端口?
有多个user-service实例地址,order-service调用时该如何选择?
order-service如何得知某个user-service实例是否依然健康,是不是已经
宕机?
这些问题都需要利用SpringCloud中的注册中心来解决,其中最广为人知的注册中
心就是Eureka,其结构如下:
现在回答前言中提出的一些问题 :
问题 1: order-service如何得知user-service实例地址?
获取地址信息的流程如下:
问题 2: order-service如何从多个user-service实例中选择具体的实例?
问题 3: order-service如何得知某个user-service实例是否依然健康,是不是已经宕机?
注意:一个微服务,既可以是服务提供者,又可以是服务消费者,因此eureka
将服务注册、服务发现等功能统一封装到了eureka-client端
Eureka 基本使用步骤如下 :
在cloud-demo父工程下,创建一个简单的 maven 子模块:
在 eureka-server 模块中引入SpringCloud为eureka提供的starter依赖:
注意 : 因为在父工程里面已经添加过 spring-cloud 的版本号了, 所以我们不需要再加版本号
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
注意 : 需要在启动类上添加注解 @EurekaApplication
注解功能
示例代码如下
package cn.knightzz.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author 王天赐
* @title: EurekaApplication
* @projectName cloud-demo
* @description:
* @website http://knightzz.cn/
* @github https://github.com/knightzz1998
* @date 2022/4/15 15:53
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
在 eureka-server 项目的 resource 目录下创建 application.yaml 文件
server:
port: 10086
spring:
application:
name: eureka-server # eureka 服务名称
eureka:
client:
service-url: # eureka 地址信息
defaultZone: http://127.0.0.1:10086/eureka
然后启动 EurekaApplication, 访问 http://127.0.0.1:10086 出现如下界面说明 Eureka 服务启动成功
根据 1.3 步骤搭建好 Eureka 服务端以后, 我们需要把其他的微服务注册到 Eureka 中
在 user-service 项目中添加依赖 :
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
在user-service中,修改application.yml文件,添加服务名称、eureka 地址:
spring:
application:
name: user-service # 项目名
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka # Eureka 服务端地址
添加配置后启动UserApplicaiton即可
如上图所示 我们可以看到 user-service 已经被注册到了 Eureka 上
我们可以通过添加SpringBoot启动配置的方式来模拟多个实例的情况 :
如上图所示 : 点击复制, 然后再 VM Option
添加 SpringBoot 端口配置 -Dserver.port=8082
然后启动即可
如上图所示 : user-service 服务已经注册成功了
服务发现就是: 假如我们的订单微服务想要调用用户微服务时,就需要先从Eureka服务端拉取user-service的信息实现服务发现
下面,我们将order-service的逻辑修改:向eureka-server拉取user-service的信息,实现服务发现。
服务发现、服务注册统一都封装在eureka-client依赖,因此这一步与服务注册时一致。
在order-service的pom文件中,引入下面的eureka-client依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
服务发现也需要知道eureka地址,因此第二步与服务注册一致,都是配置 eureka 信息:
在order-service中,修改application.yml文件,添加服务名称、eureka 地址:
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
启动 order-service 微服务后 可以在eureka服务注册中心看到
我们要去eureka-server中拉取user-service服务的实例列表,并且实现负载均衡。
实现负载均衡很简单 在order-service的OrderApplication中,给RestTemplate这个Bean添加一
个@LoadBalanced注解:
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
修改order-service服务中的cn.itcast.order.service包下的 OrderService 类中的queryOrderById方法。修改访问的url路径,用服务名代替ip、端口。
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.根据订单的用户id查询用户信息
// String url = "http://localhost:8081/user/" + order.getUserId();
// 使用微服务名代替ip和端口解决硬编问题
String url = "http://user-service/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
// 3.将用户信息封装到订单中
order.setUser(user);
return order;
}
如上面代码所示 : 我们之前使用 ip:端口
的方式, 现在我们直接使用之前定义的微服务名访问即可
spring会自动帮助我们从eureka-server端,根据userservice这个服务名称,获取实例列表,而后完成负载均衡
修改后我们可以访问 http://localhost:8080/order/101
查看返回的信息