# spring-cloud教程系列
**Repository Path**: xzm-gitee/spring-cloud-parent
## Basic Information
- **Project Name**: spring-cloud教程系列
- **Description**: spring-cloud教程系列
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-10
- **Last Updated**: 2022-02-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# spring-cloud教程系列
前言, 版本选定
```
org.springframework.boot
spring-boot-dependencies
2.2.2.RELEASE
pom
import
org.springframework.cloud
spring-cloud-dependencies
Hoxton.SR1
pom
import
```
## Eureka-服务注册与发现
### Eureka简介
Spring Cloud Eureka是Spring Cloud Netflix 子项目的核心组件之一,主要用于微服务架构中的服务治理。
在微服务架构中往往会有一个注册中心,每个微服务都会向注册中心去注册自己的地址及端口信息,注册中心维护着服务名称与服务实例的对应关系。每个微服务都会定时从注册中心获取服务列表,同时汇报自己的运行情况,
这样当有的服务需要调用其他服务时,就可以从自己获取到的服务列表中获取实例地址进行调用,Eureka实现了这套服务注册与发现机制。
### 搭建单机版Eureka注册中心
#### 引入Eureka依赖
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
```
#### 启用Euerka注册中心功能
在启动类上面加上```@EnableEurekaServer```注解
```
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class);
}
}
```
#### 配置Eureka
```
server:
port: 8001
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
client:
fetch-registry: false
register-with-eureka: false
```
- server.port: 指定eureka的端口号
- spring.application.name: 应用名称
- eureka.instance.hostname: 指定主机地址
- eureka.client.fetch-registry: 是否要从注册中心获取服务(注册中心不需要开启)
- eureka.client.register-with-eureka: 是否要注册到注册中心(注册中心不需要开启)
#### 查看Eureka的web界面
访问地址: http://localhost:8001
### 搭建集群版的Eureka注册中心
由于所有服务都会注册到注册中心去,服务之间的调用都是通过从注册中心获取的服务列表来调用,注册中心一旦宕机,所有服务调用都会出现问题。所以我们需要多个注册中心组成集群来提供服务
#### 修改host文件
找到 C:\Windows\System32\drivers\etc\ 文件夹, 在文件 **host** 末尾添加如下两行代码
```
127.0.0.1 eureka1
127.0.0.1 eureka2
```
#### eureka-node-1 配置文件
```
server:
port: 8001
spring:
application:
name: eureka-server-node1
eureka:
instance:
hostname: eureka1
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://eureka2:8002/eureka/
```
#### eureka-node-2 配置文件
```
server:
port: 8002
spring:
application:
name: eureka-server-node2
eureka:
instance:
hostname: eureka2
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://eureka1:8001/eureka/
```
#### 校验集群是否成功
节点1访问地址: http://localhost:8001/
节点2访问地址: http://localhost:8002/
### Eureka客户端搭建单节点注册
#### 导入Eureka客户端依赖
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
```
#### 启动Eureka客户端功能
在启动类上加上```@EnableDiscoveryClient```注解
```
@EnableDiscoveryClient
@SpringBootApplication
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class);
}
}
```
#### 编写单节点注册中心配置文件
```
server:
port: 9000
spring:
application:
name: producer-server
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8000/eureka/
```
- eureka.client.register-with-eureka: 是否要从注册中心获取服务
- eureka.client.fetch-registry: 是否要注册到注册中心
- eureka.client.service-url.defaultZone: 注册中心地址
启动客户端之后可以在Eureka的web页面看到服务名就表示已经注册成功了
#### 编写多节点注册中心配置文件
```
server:
port: 9001
spring:
application:
name: producer-server-register-nodes
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka1:8001/eureka/,http://eureka2:8002/eureka/
```
## Ribbon-负载均衡的服务调用
### Ribbon简介
在微服务架构中,很多服务都会部署多个,其他服务去调用该服务的时候,如何保证负载均衡是个不得不去考虑的问题。负载均衡可以增加系统的可用性和扩展性,当我们使用RestTemplate来调用其他服务时,
Ribbon可以很方便的实现负载均衡功能。
### 导入依赖
```
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
```
### 配置RestTemplate
```
@Configuration
public class RibbonConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
```
### Ribbon常用配置
```
ribbon:
ConnectTimeout: 1000
ReadTimeout: 3000
OkToRetryOnAllOperations: true
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
```
- ribbon.ConnectTimeout: 服务请求连接超时时间(毫秒)
- ribbon.ReadTimeout: 服务请求处理超时时间(毫秒)
- ribbon.OkToRetryOnAllOperations: 对超时请求启用重试机制
- ribbon.MaxAutoRetriesNextServer: 切换重试实例的最大个数
- ribbon.MaxAutoRetries: 切换实例后重试最大次数
- ribbon.NFLoadBalancerRuleClassName: 修改负载均衡算法
### Ribbon的负载均衡策略
- com.netflix.loadbalancer.RandomRule:从提供服务的实例中以随机的方式;
- com.netflix.loadbalancer.RoundRobinRule:以线性轮询的方式,就是维护一个计数器,从提供服务的实例中按顺序选取,第一次选第一个,第二次选第二个,以此类推,到最后一个以后再从头来过;
- com.netflix.loadbalancer.RetryRule:在RoundRobinRule的基础上添加重试机制,即在指定的重试时间内,反复使用线性轮询策略来选择可用实例;
- com.netflix.loadbalancer.WeightedResponseTimeRule:对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择;
- com.netflix.loadbalancer.BestAvailableRule:选择并发较小的实例;
- com.netflix.loadbalancer.AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例;
- com.netflix.loadbalancer.ZoneAwareLoadBalancer:采用双重过滤,同时过滤不是同一区域的实例和故障实例,选择并发较小的实例。
## Hystrix-服务容错保护
### Hystrix 简介
在微服务架构中,服务与服务之间通过远程调用的方式进行通信,一旦某个被调用的服务发生了故障,其依赖服务也会发生故障,此时就会发生故障的蔓延,最终导致系统瘫痪。Hystrix实现了断路器模式,
当某个服务发生故障时,通过断路器的监控,给调用方返回一个错误响应,而不是长时间的等待,这样就不会使得调用方由于长时间得不到响应而占用线程,从而防止故障的蔓延。
Hystrix具备服务降级、服务熔断、线程隔离、请求缓存、请求合并及服务监控等强大功能。
### 导入Hystrix依赖
```
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
```
### 开启服务容错
```@EnableCircuitBreaker```
```
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class);
}
}
```
### 编写服务容错的方法
```
public String handle() {
return "服务出错, 已经降级处理";
}
```
### 调用服务容错
```
@GetMapping("/error")
@HystrixCommand(fallbackMethod = "handle")
public String error() {
return "现在是【" + port + "】给您提供服务";
}
```
### @HystrixCommand中的常用参数
- fallbackMethod:指定服务降级处理方法;
- ignoreExceptions:忽略某些异常,不发生服务降级;
- commandKey:命令名称,用于区分不同的命令;
- groupKey:分组名称,Hystrix会根据不同的分组来统计命令的告警及仪表盘信息;
- threadPoolKey:线程池名称,用于划分线程池。
### Hystrix的请求缓存
当系统并发量越来越大时,我们需要使用缓存来优化系统,达到减轻并发请求线程数,提供响应速度的效果。
- @CacheResult:开启缓存,默认所有参数作为缓存的key,cacheKeyMethod可以通过返回String类型的方法指定key;
- @CacheKey:指定缓存的key,可以指定参数或指定参数中的属性值为缓存key,cacheKeyMethod还可以通过返回String类型的方法指定;
- @CacheRemove:移除缓存,需要指定commandKey。
### Hystrix请求合并
微服务系统中的服务间通信,需要通过远程调用来实现,随着调用次数越来越多,占用线程资源也会越来越多。Hystrix中提供了@HystrixCollapser用于合并请求,从而达到减少通信消耗及线程数量的效果。
- batchMethod:用于设置请求合并的方法;
- collapserProperties:请求合并属性,用于控制实例属性,有很多;
- timerDelayInMilliseconds:collapserProperties中的属性,用于控制每隔多少时间合并一次请求;
### Hystrix的常用配置
```
hystrix:
command:
default:
execution:
isolation:
strategy: THREAD
thread:
timeoutInMilliseconds: 1000
interruptOnTimeout: true
interruptOnCancel: true
timeout:
enabled: true
semaphore:
maxConcurrentRequests: 10
fallback:
enabled: true
```
- timeoutInMilliseconds: 执行的超时时间,执行超过该时间会进行服务降级处理
- interruptOnTimeout: 执行超时的时候是否要中断
- interruptOnCancel: 执行被取消的时候是否要中断
- timeout.enable: 是否启用超时时间
- fallback.enabled: 是否启用服务降级
## Hystrix Dashboard-断路器监控
### Hystrix Dashboard简介
Hystrix提供了Hystrix Dashboard来实时监控HystrixCommand方法的执行情况。 Hystrix Dashboard可以有效地反映出每个Hystrix实例的运行情况,帮助我们快速发现系统中的问题,从而采取对应措施。
### 搭建Hystrix Dashboard
导入依赖
```
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
```
开启配置
```
@EnableHystrixDashboard
@EnableDiscoveryClient
@SpringBootApplication
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class);
}
}
```
访问监控地址: http://localhost:9200/hystrix/
### Hystrix监控服务
导入依赖
```
org.springframework.boot
spring-boot-starter-actuator
```
配置Hystrix
```
@Configuration
public class HystrixConfig {
@Bean
public ServletRegistrationBean bean() {
HystrixMetricsStreamServlet servlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean bean = new ServletRegistrationBean(servlet);
bean.setLoadOnStartup(1);
bean.addUrlMappings("/hystrix.stream");
bean.setName("HystrixMetricsStreamServlet");
return bean;
}
}
```
查看监控
http://localhost:9000/hystrix.stream
## OpenFeign-声明式服务调用
### Feign简介
Feign是声明式的服务调用工具,我们只需创建一个接口并用注解的方式来配置它,就可以实现对某个服务接口的调用,简化了直接使用RestTemplate来调用服务接口的开发量。
### 导入依赖
```
org.springframework.cloud
spring-cloud-starter-openfeign
```
### 简单跨服务调用
启动类上开启feign的客户端功能: ```@EnableFeignClients```
```
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class);
}
}
```
服务接口绑定
```
@FeignClient(value = "producer-server")
public interface ProducerFeign {
@GetMapping("/get")
public String get();
}
```
服务调用
```
@Autowired
private ProducerFeign prodducerFeign;
@GetMapping("/get")
public String get() {
return prodducerFeign.get();
}
```
### feign的常用配置
#### 服务容错降级处理
```
feign:
hystrix:
enabled: true
```
编写一个类继承被绑定的服务接口, 然后在里面实现降级处理
```
@Component
public class ProducerFeignFallback implements ProducerFeign {
@Override
public String get() {
return "系统繁忙, 请稍后再试";
}
}
```
在服务接口配置容错处理
```
@FeignClient(value = "producer-server", fallback = ProducerFeignFallback.class)
public interface ProducerFeign {
@GetMapping("/get")
public String get();
}
```
#### 超时配置
```
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000
```
#### 日志配置
```
logging:
level:
com.ming.feign.feign: debug
```
#### feign的拦截器
```
@Bean
public RequestInterceptor requestInterceptor() {
return (template -> {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
if (request != null) {
String authorization = request.getHeader("Authorization");
if (authorization != null) {
template.header("Authorization",authorization);
}
}
}
});
}
```
## Zuul-服务网关
### zuul简介
API网关为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。
它实现了请求路由、负载均衡、校验过滤、服务容错、服务聚合等功能。
### 导入依赖
```
org.springframework.cloud
spring-cloud-starter-netflix-zuul
```
### API路由
#### 配置文件
```
server:
port: 80
spring:
application:
name: zuul-server
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8000/eureka/
```
#### 开启api路由功能
```
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class);
}
}
```
#### 配置路由
```
zuul:
routes:
open-feign-server:
path: /feign/**
```
- open-feign-server: 服务名
- path: 路由规则
### 过滤器
#### 过滤器类型:
zuul的过滤器类型都在```FilterConstants``类里面
- PRE_TYPE: 在请求被路由到目标服务前执行,比如权限校验、打印日志等功能;
- ROUTE_TYPE: 在请求被路由到目标服务时执行,这是使用Apache HttpClient或Netflix Ribbon构建和发送原始HTTP请求的地方;
- POST_TYPE: 在请求被路由到目标服务后执行,比如给目标服务的响应添加头信息,收集统计数据等功能;
- ERROR_TYPE: 请求在其他阶段发生错误时执行。
#### 自定义过滤器
```
@Component
public class LoggerFilter extends ZuulFilter {
private Logger logger = LoggerFactory.getLogger(LoggerFilter.class);
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
StringBuffer url = request.getRequestURL();
logger.info("url:{}", url);
return null;
}
}
```
### Ribbon和Hystrix的支持
由于Zuul自动集成了Ribbon和Hystrix,所以Zuul天生就有负载均衡和服务容错能力,我们可以通过Ribbon和Hystrix的配置来配置Zuul中的相应功能。
使用Hystrix的配置来设置路由转发时HystrixCommand的执行超时时间
```
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000
```
使用Ribbon的配置来设置路由转发时请求连接及处理的超时时间
```
ribbon:
ConnectTimeout: 1000
ReadTimeout: 3000
```
## Config-集中户配置
## Bus-消息总线
## Sleuth-链路追踪
## Gateway-新一代API网关
## Oauth2-微服务权限