在分布式架构中,所有的必须服务都先注册,然后服务间的调用通过注册中心获取到调用地址才能进行。
这种模式下,在部署的时候服务间不用关注的ip地址、端口信息,因为这些都可以通过注册中心获取到,大大方便了部署。
Eureka 注册中心
Eureka 是 Netflix 开发的服务发现组件,本身是一个基于 REST 的服务。Spring Cloud 将它集成在其子项目 spring-cloud-netflix 中,以实现 Spring Cloud 的服务注册与发现,同时还提供了负载均衡、故障转移等能力。
创建一个maven项目,pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.CHIV</groupId>
<artifactId>eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka</name>
<description>spring cloud demo by eureka</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencies>
<!--eureka-server 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
EurekaApplication 中增加@EnableEurekaServer注解
配置文件如下
server:
port: 9000 #指定运行端口
spring:
application:
name: eureka-server #指定服务名称
eureka:
instance:
hostname: localhost #指定主机地址
client:
fetch-registry: false #指定是否要从注册中心获取服务(注册中心不需要开启)
register-with-eureka: false #指定是否要注册到注册中心(注册中心不需要开启)
server:
enable-self-preservation: false #关闭保护模式
启动后,访问http://localhost:9000/可以浏览到注册中心的。
客户端注册
创建一个新的maven项目,将上方的pom文件的spring-cloud-starter-netflix-eureka-server 替换为spring-cloud-starter-netflix-eureka-client
配置文件
server:
port: 8101
spring:
application:
name: test-eureka-client
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
# 注册中心地址
defaultZone: http://localhost:9000/eureka/
入口文件增加@EnableEurekaClient注解,启动后就可以在注册中心,注册列表中看到了。
服务调用
Ribbon + RestTemplate 实现服务的调用。
当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。
服务提供者
pom.xml文件中添加web力能
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.yml 没有什么特别,就是把服务注册到注册中心就可以了。
server:
port: 8101
spring:
application:
name: test-eureka-client
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
# 注册中心地址
defaultZone: http://localhost:9000/eureka/
我们编写的接口一定是返回json格式的对象。
编写一个web接口,访问http://localhost:8101/person/list 可以返回[{"name":"小明"}]
@RestController
@RequestMapping("person")
public class PersonController {
@GetMapping("list")
public Object getList(){
return "[{\"name\":\"小明\"}]"; }}
消费者
添加ribbon依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
application.yml中增加ribbon配置
# 服务提者名称
service-url: http://ribbon-copy
ribbon:
ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
OkToRetryOnAllOperations: true #对超时请求启用重试机制
MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
MaxAutoRetries: 1 # 切换实例后重试最大次数
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
配置RestTemplate
@Configuration
public class RibbonConfig {
@Bean
//启动ribbon均衡负载
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
编写测试接口
@RestController
@RequestMapping("test")
public class TestRibbonController {
@Autowired
RestTemplate restTemplate;
@Value("${service-url}")
String serviceUrl;
@GetMapping("ribbon")
public Object getList(){
return restTemplate.getForEntity(serviceUrl+"/person/list",Object.class);
}
}
启动后,访问http://localhost:8104/test/ribbon 就能看到 [{"name":"小明"}]