现存两个项目:订单模块
order-service
和 用户模块user-service
目标:查询订单的时候,将订单所属的用户信息也查询出来,此时order-service
就要远程调用user-service
的接口,获取到用户信息,然后放入订单订单信息中返回结果,如下:
{
"id": 106,
"price": 544900,
"name": "美的(Midea) 新能效 冷静星II ",
"num": 1,
"userId": 6,
"user": {
"id": 6,
"username": "范兵兵",
"address": "山东省青岛市"
}
}
方案:使用Eureka注册中心
搭建Eureka注册中心
创建一个maven项目,名称
eureka-server
导入依赖
引入SpringCloud为eureka提供的starter依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
编写启动类
给eureka-server
服务编写一个启动类,一定要添加一个@EnableEurekaServer
注解,开启eureka
的注册中心功能:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
编写配置文件
编写一个application.yml文件,内容如下:
server:
port: 10086
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
启动服务
启动微服务,然后在浏览器访问:http://127.0.0.1:10086
看到下面结果应该是成功了:
服务注册
将user-service注册到eureka-server中去。
在user-service
的pom.xml
文件中,引入下面的eureka-client
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在
user-service
中,修改application.yml
文件,添加服务名称、eureka地址:
spring:
application:
name: userservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
为了演示一个服务有多个实例的场景,我们添加一个SpringBoot的启动配置,再启动一个
user-service
新增几个如下,分别对应不同的端口:
服务发现
将
order-service
的逻辑修改:向eureka-server
拉取user-service
的信息,实现服务发现
服务发现、服务注册统一都封装在eureka-client
依赖,因此这一步与服务注册时一致。
在order-service
的pom.xml
文件中,引入下面的eureka-client
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置文件
服务发现也需要知道eureka
地址,因此第二步与服务注册一致,都是配置eureka
信息:
在order-service
中,修改application.yml
文件,添加服务名称、eureka
地址:
spring:
application:
name: orderservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
服务拉取、负载均衡
最后,要去eureka-server
中拉取user-service
服务的实例列表,并且实现负载均衡。
不过这些动作不用我们去做,只需要添加一些注解即可。
在order-service
的OrderApplication
中,给RestTemplate
这个Bean
添加一个@LoadBalanced
注解:
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
/**
* 创建RestTemplate,并注入Spring容器
* @return
*/
@Bean
@LoadBalanced //开启负债均衡,默认是轮询模式
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
修改
order-service
服务中的OrderService
类中的queryOrderById
方法
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.查询用户信息,远程调用,放弃http请求,将这里换成上面的服务名称就好了:userservice
String url = "http://userservice/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
// 3.封装User到Order
order.setUser(user);
// 4.返回
return order;
}
最终启动
Eureka
假如我们的服务提供者
user-service
部署了多个实例,如图:
思考几个问题:
order-service
在发起远程调用的时候,该如何得知user-service
实例的ip地址和端口?- 有多个
user-service
实例地址,order-service
调用时该如何选择? order-service
如何得知某个user-service
实例是否依然健康,是不是已经宕机?
这些问题都需要利用SpringCloud中的注册中心来解决,其中最广为人知的注册中心就是Eureka
,其结构如下:
问题1:order-service
如何得知user-service
实例地址?
获取地址信息的流程如下:
user-service
服务实例启动后,将自己的信息注册到eureka-server
(Eureka服务端)。这个叫服务注册eureka-server
保存服务名称到服务实例地址列表的映射关系order-service
根据服务名称,拉取实例地址列表。这个叫服务发现或服务拉取
问题2:order-service
如何从多个user-service
实例中选择具体的实例?
order-service
从实例列表中利用负载均衡算法选中一个实例地址- 向该实例地址发起远程调用
问题3:order-service
如何得知某个user-service
实例是否依然健康,是不是已经宕机?
user-service
会每隔一段时间(默认30秒)向eureka-server
发起请求,报告自己状态,称为心跳- 当超过一定时间没有发送心跳时,
eureka-server
会认为微服务实例故障,将该实例从服务列表中剔除 order-service
拉取服务时,就能将故障实例排除了
注意:一个微服务,既可以是服务提供者,又可以是服务消费者,因此eureka将服务注册、服务发现等功能统一封装到了eureka-client端