如果商品是一个独立的服务,订单系统也是一个独立的服务,那么它们直接怎么进行交互呢?虽然使用springboot也可以实现两个服务之间的交互但是存在url硬编码问题(ip地址修改需要修改配置文件),并且性能低下。
那应该怎么解决呢? – 通过服务注册、发现的机制来完成。
一、微服务注册与发现
由上图可以看出:
1、服务提供者将服务注册到注册中心
2、服务消费者通过注册中心查找服务
3、查找到服务后进行调用(这里就是无需硬编码url的解决方案)
4、服务的消费者与服务注册中心保持心跳连接,一旦服务提供者的地址发生变更时,注册中心会通知服务消费者。
二、注册中心:Eureka
从Eureka 2.0开始Eureka就已经闭源了,不过对国内影响很小,一方面是因为国内很多都使用Eureka 1.X 系列,另一方面是因为Spring Cloud提供了多种注册中心的支持,如:consul、ZooKeeper等,如图所示:
三、原理
Eureka包含两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就别一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
1.编写Eureka Server
第一步:创建SpringBoot工程:
点击“Next”,之后完成创建。
第二步,导入依赖(springboot工程创建中已有依赖):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies> </dependencyManagement>
|
第三步,编写程序启动类:
@SpringBootApplication @EnableEurekaServer //表示是一个Eureka服务注册中心 public class AppEureka {
public static void main(String[] args) { SpringApplication.run(AppEureka.class, args); } }
|
第四步,编写application.yml配置文件:
# 服务器端口号配置 server: port: 8100 # 服务名称 spring: application: name: eureka-service eureka: instance: #注册中心地址 hostname: localhost
#客户端调用地址配置 client: # client访问注册服务中心地址 service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
#是否从Eureka中获取注册信息,因为自己为注册中心,不会在该应用中的检索服务信息 fetch-registry: false #是否将自己注册到Eureka服务中,因为该应用本身就是注册中心,不需要再注册自己(集群的时候为true) register-with-eureka: false
|
第五步,启动程序做测试:
2.将商品微服务注册到Eureka
接下来,我们需要将商品的微服务注册到Eureka服务中。
第一步:修改pom文件,引入Spring Cloud的管理依赖以及eureka服务依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies> </dependencyManagement>
|
第二步,修改application.yml配置文件:
#服务端口号(本身是一个web项目) server: port: 8081 #起个名字作为服务名称(该服务注册到eureka注册中心的名称,比如商品服务) spring: application: name: app-item #服务注册到eureka注册中心的地址 eureka: client: service-url: defaultZone: http://localhost:8100/eureka
#因为该应用为服务提供者,是eureka的一个客户端,需要注册到注册中心 register-with-eureka: true #是否需要从eureka上检索服务 fetch-registry: true
# 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的 instance: prefer-ip-address: true
|
第三步,修改启动类,增加@EnableEurekaClient 注解:
@SpringBootApplication // 声明为Eureka的客户端 @EnableEurekaClient public class ItemApp{
public static void main(String[] args) { SpringApplication.run(ItemApp.class, args); }
}
|
第四步,启动测试:
3.订单系统从Eureka中发现商品服务
第一步,在订单系统中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies> </dependencyManagement>
|
第二步,修改application.yml配置文件:
#服务端口 server: port: 8082 #起个名字作为服务名称(该服务注册到eureka注册中心的名称,比如订单服务) spring: application: name: app-order #服务注册到eureka注册中心的地址 eureka: client: service-url: defaultZone: http://localhost:8100/eureka
#因为该应用为服务提供者,是eureka的一个客户端,需要注册到注册中心 register-with-eureka: true #是否需要从eureka上检索服务 fetch-registry: true
# 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的 instance: prefer-ip-address: true
|
第三步,在启动类中添加@EnableEurekaClient注解 ,获取RestTemplate的方法上加 @LoadBalanced注解
@SpringBootApplication @EnableEurekaClient public class OrderApp {
public static void main(String[] args) { SpringApplication.run(OrderApp.class, args); }
/** * 向Spring容器中定义RestTemplate对象 * @return */ @Bean @LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate(); } }
|
第四步,修改ItemService的实现逻辑:
@Service public class ItemService {
// Spring框架对RESTful方式的http请求做了封装,来简化操作 @Autowired
private RestTemplate restTemplate;
public Item queryItemById(Long id) {
// 该方法走eureka注册中心调用(去注册中心根据app-item查找服务,这种方式必须先开启负载均衡@LoadBalanced) String itemUrl = "http://app-item/item/{id}"; Item result = restTemplate.getForObject(itemUrl, Item.class, id); System.out.println("订单系统调用商品服务,result:" + result);
return result; } }
|
第五步,启动测试(此时有3个应用:Eureka注册中心、Item服务、order服务)
在注册中心http://localhost:8100看到有2个客户端:
4.订单系统从Eureka中发现商品服务2(Fegin的使用)
Feign是一种负载均衡的HTTP客户端, 使用Feign调用API就像调用本地方法一样,从而避免了调用目标微服务时,需要不断的解析/封装json数据的繁琐。
Fegin是一个声明似的web服务客户端,它使得编写web服务客户端变得更加容易。使用Fegin创建一个接口并对它进行注解。它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign。
GitHub地址:https://github.com/OpenFeign/feign
(1)导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
(2)开启Feign功能
@SpringBootApplication @EnableEurekaClient
//开启Feign功能 @EnableFeignClients public class OrderApp {
public static void main(String[] args) { SpringApplication.run(OrederApplication.class, args); }
}
|
(3)修改ItemService逻辑
@FeignClient("app-item") public interface ItemService {
@PostMapping("/item")
public Item queryItemById(@RequestParam("id") Long id);
//Restful API调用
@PostMapping("/item/{id}")
public Item queryItemById2(@RequestParam("id") Long id);
}
|
(4)使用ItemService
@RestController public class OrderController {
@Resource
ItemService itemService;
...
|