Spring最擅长的就是集成,把世界上最好的框架拿过来,集成到自己的项目中。
Spring Cloud也是一样,它将现在非常流行的一些技术整合到一起,实现了诸如:配置管理,服务发现,智能路
由,负载均衡,熔断器,控制总线,集群状态等等功能。其主要涉及的组件包括:
Netflix
Eureka:注册中心
Zuul:服务网关
Ribbon:负载均衡
Feign:服务调用
Hystrix:熔断器
例子
1. 把以往单体架构的的项目里面有N个模块
2. 我们单独把中间的几个业务拿出来分为N个小模块
3. 两个模块分别是 用户模块和订单模块
4. 现在调用两个模块中间是没有任何关联的
5. 当我们想用端口号为8080的订单服务调用端口号为8081的查询用户API时,我们把两个模块分为两个项目来写,我们如何来实现远程调用呢?
微服务调用方式
1. 注册RestTemplate
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
/** * 创建RestTemplate并注入Spring容器 * @return */
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2. 服务远程调用RestTemplate
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.利用RestTemplate发起HTTP请求,查询用户
String url="http://localhost:8081/user/"+order.getUserId();
// 2.1发送HTTP请求,实现远程调用,
// 第二个参数 告诉RestTemplate我们返回的是User对象,他会自动帮我们把JSON反序列化成User类型
User user = restTemplate.getForObject(url, User.class);
// 3. 将我们远程调用得到的数据封装到Order中
order.setUser(user);
// 4.返回
return order;
}
}
1. 引入Eureka依赖
<dependency>
<!--eureka服务端依赖 -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2. 编写启动类,添加 @EnableEurekaServer //开启Eureka服务
3. 添加application.yml添加配置文件
spring:
application:
name: eurekaserver #Eureka的服务名称
eureka:
client:
service-url: #eureka地址信息
defaultZone: http://127.0.0.1:10086/eureka
4. 启动成功,打开我们application.yml中eureka的defaultZone:定义的地址就能看见服务
1. 引入Eureka客户端依赖
<!--引入 eureka客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2. 添加application.yml添加配置文件
spring:
application:
name: userService #User服务端名称
eureka:
client:
service-url: #eureka地址信息
defaultZone: http://127.0.0.1:10086/eureka
1. 修改访问的URL路径,用服务名代替IP、端口
String url="http://userservice:8081/user/"+order.getUserId();
2. 在启动类中的RestTemplate添加负载均衡注解 @LoadBalanced //开启负载均衡
/** * 创建RestTemplate并注入Spring容器 * @return */
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
1. 使用发现客户端
@Autowired
private DiscoveryClient discoveryClient;
2. 拼接url
//拉取服务
List<ServiceInstance> userService = discoveryClient.getInstances("userService");
ServiceInstance serviceInstance = userService.get(0);
//拼接url
String url="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/user/"+id;
3. 在启动类上开启 发现服务注解
@EnableDiscoveryClient //开启eureka客户端发现功能
Ribbon默认采用懒加载,即第一次访问时才回去创建LoadBalanceClient,请求时间会很长
而饥饿加载则会在项目启动时就创建,降低第一次访问的耗时
1.配置饥饿加载
ribbon:
eager-load:
enabled: true #开启饥饿加载
clients: userservice #指定饥饿加载的服务名称
用户的请求故障时,不会被阻塞,更不会无休止的等待或者看到系统崩溃,至少可以看到一个执行结果(例如返回
友好的提示信息) 。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
@EnableCircuitBreaker 开启熔断
@RestController
@RequestMapping("/consumer")
@Slf4j
public class ConsumerController {![在这里插入图片描述](http://img.saoniuhuo.com/images/202110/45201633617197417.jpg)
@Autowired
public RestTemplate restTemplate;
@GetMapping("{id}")
//当请求超时,执行指定的服务降级方法
@HystrixCommand(fallbackMethod = "fallback")
public String getUser(@PathVariable Long id){
return restTemplate.getForObject("http://userservice/user/"+id,String.class);
}
public String fallback(Long id){
return "网络拥挤,请稍后再试!!!";
}
}
要注意;因为熔断的降级逻辑方法必须跟正常逻辑方法保证:相同的参数列表和返回值声明。
public String defaultFallback() {
return "默认提示:对不起,网络太拥挤了!";
}
在服务熔断中,使用的熔断器,也叫断路器,其英文单词为:Circuit Breaker 熔断机制与家里使用的电路熔断原理
类似;当如果电路发生短路的时候能立刻熔断电路,避免发生灾难。在分布式系统中应用服务熔断后;服务调用方
可以自己进行判断哪些服务反应慢或存在大量超时,可以针对这些服务进行主动熔断,防止整个系统被拖垮。
Hystrix的服务熔断机制,可以实现弹性容错;当服务请求情况好转之后,可以自动重连。通过断路的方式,将后续
请求直接拒绝,一段时间(默认5秒)之后允许部分请求通过,如果调用成功则回到断路器关闭状态,否则继续打
开,拒绝请求的服务。
1. 在 Nacos的bin目录下cmd命令行输入 单击模式命令行
startup.cmd -m standalone
2. 启动完毕后
3. 在网页打开
http://本机ip:8848/nacos/index.html 登陆账号密码 都是 nacos
1.在父工程中添加Nacos管理依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
2. 在子模块中导入 nacos客户端依赖
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
3. 在application核心文件中配置nacos地址
spring:
cloud:
nacos:
server-addr: localhost:8848 #nacos服务地址
1. 在application中添加集群名称
spring:
discovery:
cluster-name: HZ #集群名称 这里代表杭州
当A模块向B模块发送请求时,会优先查看A模块和B模块是否在同一个集群中,若在同一个集群中发送数据延迟会大大降低
实例的权重控制:
1. Nacos控制台可以设置实例的权重值,0~1之间
2. 同集群内的多个实例,权重越高访问的频率越高
3. 权重为0则完全不会访问
1. namespace用来做环境隔离
2. 每个namespace都有唯一的ID
3. 不同namespace下的服务不可见,无法跨namespace调用服务
4. 在application核心配置文件写入当前业务模块所在的命名空间
spring:
cloud:
nacos:
discovery:
namespace: #命名空间的ID
拉取Nacos上的配置中心的设置 具体配置看3.6.1的图2
@Value("${pattern.dateformat}") //${"获取Nacos配置中心的值"}
private String format;
@RequestMapping("now")
public void now(){
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern(format)));
}
在@Value("${Nacos配置中心的属性}")注解的类上添加@RefreshScope
方式二:推荐
@Data
@Component
@ConfigurationProperties(prefix = "pattern")//获取配置文件前缀
public class PatternProperties {
//如果前缀和当前属性拼接上在配置中心存在的话,就会自动注入到该属性
private String format;
}
@Data
@Component
@ConfigurationProperties(prefix = "pattern")//获取配置文件前缀
public class PatternProperties {
//如果前缀和当前属性拼接上在配置中心存在的话,就会自动注入到该属性
private String format;
private String envSharedValue;
}
@GetMapping("/env")
private Object Share(){
return patternProperties;
}
1. 导入依赖
<!-- openFeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 启动类上添加Feign的开启注解
@EnableFeignClients //开启openFeign
3. 定义openFeign接口
@FeignClient("userService")//要求与Nacos中的服务名一致
public interface UserClient {
@GetMapping("/user/{id}")//暴露userService微服务的请求方法
User findById(@PathVariable("id") Long id);
}
4. 调用
@Autowired
public UserClient userClient;
public Order openFeign(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
//2.利用Feign实现远程调用
User user = userClient.findById(order.getUserId());
order.setUser(user);
// 4.返回
return order;
}
方式一: 配置文件方式
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL #日志级别
方式二: java代码方式,需要先声明一个Bean:
public class FeignClientConfiguration {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
而后如果是全局配置,则把它放到@EnableFeignClients这个注解中:
@EnableFeignClients(defaultConfiguration = FeignAutoConfiguration.class)
而后如果是全局配置,则把它放到@EnableFeignClients这个注解中: | @EnableFeignClients(defaultConfiguration = FeignAutoConfiguration.class) |
---|---|
如果是局部配置,则把它放到@FeignClient这个注解中: | @FeignClient(value = “userService”,configuration = FeignAutoConfiguration.class) |
1. 添加网关依赖和nacos服务发现依赖
<!--网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2. application核心文件设置网关配置
server:
port: 10010 #网关端口
spring:
application:
name: gateway #服务名称
cloud:
nacos:
server-addr: localhost:8848 #nacosnacos地址
gateway:
routes: #网关路由配置
- id: user-service #路由id,自定义,只要唯一即可
uri: lb://userService #路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: #路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** #这个是按照路径匹配,只要以/user/开头就符合要求 - id: order-service uri: lbb://orderService predicates: - Path=/order/**
官网:
过滤器名称 | 说明 |
---|---|
AddRequestHeader | 对匹配的上的请求添加请求头 |
AddRequestParameters | 对匹配上的路由添加请求参数 |
AddResponseHeader | 从网关返回的请求添加响应头 |
StripPrefix | 对匹配上的请求取出前缀 |
server:
port: 10010 #网关端口
spring:
application:
name: gateway #服务名称
cloud:
nacos:
server-addr: localhost:8848 #nacosnacos地址
gateway:
routes: #网关路由配置
- id: user-service #路由id,自定义,只要唯一即可
uri: lb://userService #路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: #路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** #这个是按照路径匹配,只要以/user/开头就符合要求
filters:
- AddRequestHeader=Truth,yyds
- AddResponseHeader=Truth,yyds
- id: order-service
uri: lb://orderService
predicates:
- Path=/order/**
spring:
application:
name: gateway #服务名称
cloud:
nacos:
server-addr: localhost:8848 #nacosnacos地址
gateway:
routes: #网关路由配置
- id: user-service #路由id,自定义,只要唯一即可
uri: lb://userService #路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: #路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** #这个是按照路径匹配,只要以/user/开头就符合要求
- id: order-service
uri: lb://orderService
predicates:
- Path=/order/**
default-filters: #默认过滤器,对所有路由都生效
- AddRequestHeader=Truth,yyds #添加请求头
- AddResponseHeader=Truth,yyds #添加响应头
1. 实现GlobalFilter接口的方法
2. 标记当前的全局过滤器优先级 @Order
@Order(-1)//决定了GlobalFilter全局过滤器的优先级,数字越小,优先级越高
@Component
public class AuthorizationFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = request.getQueryParams();
//2.获取参数中的第一个为authorization的值
String authorization = queryParams.getFirst("authorization");
//3.判断是否相等
if("admin".equals(authorization)){
//4.相等 放行
return chain.filter(exchange);//若有下一个全局过滤器就执行下一个全局过滤器
}
//5.否 拦截
//5.1设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//5.2拦截请求
return exchange.getResponse().setComplete();
}
}
在分布式系统中,由于服务数量非常多,配置文件分散在不同的微服务项目中,管理不方便。为了方便配置文件集
中管理,需要分布式配置中心组件。在Spring Cloud中,提供了Spring Cloud Config,它支持配置文件放在配置服
务的本地,也支持放在远程Git仓库(GitHub、码云)。
命名方式:配置文件的命名方式:{application}-{profile}.yml 或 {application}-{profile}.properties
application为应用名称
profile用于区分开发环境,测试环境、生产环境等
config模块导入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
@EnableConfigServer 开启配置模块
server:
port: 12000
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: 填写Git仓库的地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
spring:
cloud:
config:
# 要与仓库中的配置文件的application保持一致
name: user
# 要与仓库中的配置文件的profile保持一致
profile: dev
# 要与仓库中的配置文件所属的版本(分支)一样
label: master
discovery:
# 使用配置中心
enabled: true
# 配置中心服务名
service-id: config-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/m0_50677223/article/details/119987109
内容来源于网络,如有侵权,请联系作者删除!