Spring Cloud 是⼀个基于SpringBoot实现的微服务架构应用开发框架,它为我们进行微服务架构应用开发提
供了服务注册与发现、熔断器、网关路由、配置管理、负载均衡、消息总线、数据监控等⼀系列工具。
Spring Cloud核心组件
Eureka—服务注册与发现中心:服务提供者将服务注册到这里,服务消费者在这里调用服务。
Eureka可靠性—可以实现Eureka集群,防止单个节点挂掉,Eureka集群搭建。
Eureka安全性—Spring Security安全框架,设置帐号和密码来限制服务的注册及发现。
服务提供者:以一个标准来划分的service服务。例如以对数据库进行一次操作就划分为一个服务。(是一个完整的springboot模块,可以理解为将单体项目中dao层对数据库的一个增删改查操作提取出来作为一个单独的springboot模块,整个项目只有这一个业务供别人调用)
服务消费者:提供面向前端的api接口,供前端访问(也是一个完整的springboot模块,调用一个或多个服务提供者模块来完成一整个大的操作业务功能,可以理解为单体项目中的controller中的一个业务)
太新的版本可能不好使 (下面的都好使)
springboot 2.5.9 2.4.4
spring-cloud 2021.0.0 2020.0.5
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
## 设置服务注册与发现中⼼的端⼝
server:
port: 8761
## 在微服务架构中,服务注册中⼼是通过服务应⽤的名称来区分每个服务的
## 我们在创建每个服务之后,指定当前服务的 应⽤名/项⽬名
spring:
application:
name: service-eureka
eureka:
client:
## 192.168.54.59这个ip如果是集群就填写要注册到别的eureka的ip地址,
## 否则默认ip是本地localhost,端口号是8761
service-url:
defaultZone: http://192.168.54.59:8761/eureka
## 设置服务注册与发现中⼼是否为为集群搭建(如果为集群模式,多个eureka节点之间需要相互注册)
register-with-eureka: false
## 设置服务注册与发现中是否作为服务进⾏注册
fetch-registry: false
@SpringBootApplication
@EnableEurekaServer
public class ServiceEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceEurekaApplication.class, args);
}
}
当完成Eureka的搭建之后,只要知道ip和port就可以随意的注册服务、调用服务,这是不安全的,我们可以
通过设置帐号和密码来限制服务的注册及发现。
在eureka中整合Spring Security安全框架实现帐号和密码验证
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
## 设置访问eureka的帐号和密码
spring:
security:
user:
name: zhangsan
password: 123456
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
//设置当前服务器的所有请求都要使⽤spring security的认证
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
## 服务提供者和服务消费者的eureka yml配置都要加账号密码才能访问到服务与注册中心
eureka:
client:
service-url:
defaultZone: http://zhangsan:123456@localhost:8761/eureka
将能够完成特定业务的SpringBoot应用作为服务提供者,注册到服务注册与发现中心
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
## 当前服务的port
server:
port: 9001
## 当前应⽤名会作为服务唯⼀标识注册到eureka
spring:
application:
name: order-add
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_2010_sc?characterEncoding=utf-8
username: root
password: admin123
mybatis:
mapper-locations: classpath:mappers/*
type-aliases-package: com.qfedu.order.beans
## 配置Eureka服务注册与发现中⼼的地址
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
@SpringBootApplication
@MapperScan("com.qfedu.order.dao")
@EnableEurekaClient
public class OrderAddApplication {
public static void main(String[] args) {
SpringApplication.run(OrderAddApplication.class, args);
}
}
Feign是基于Ribbon和Hystrix的封装
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
server:
port: 8002
spring:
application:
name: api-order-add-feign
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
## 启⽤熔断器机制
## 老版本这么写
feign:
hystrix:
enabled: true
## 新版本
feign:
circuitbreaker:
enabled: true
## 设置熔断器服务降级时间 (默认 1000)
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 8000
@SpringBootApplication
@EnableDiscoveryClient //声明为服务消费者
@EnableFeignClients //声明启⽤feign客户端
@EnableHystrix //声明启⽤熔断器
public class ApiOrderAddFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ApiOrderAddFeignApplication.class, args);
}
}
使用Feign进行服务调用的时候,需要手动创建⼀个服务访问客户端(接口)
配置一个服务降级处理类
//与服务提供者注册的application:name相同,fallback 指向对应服务降级类
@FeignClient(value = "order-add", fallback = OrderAddClientFallback.class)
public interface OrderAddClient {
//路径为服务提供者的服务访问地址 抽象方法与服务相同
@PostMapping("order/add")
public ResultVO addOrder(Order order);
}
FeignClient的服务降级类:1.必须实现Feign客户端接⼝,2.必须交给Spring容器管理
@Component
public class OrderAddClientFallback implements OrderAddClient {
public ResultVO addOrder(Order order) {
System.out.println("-------addOrder的降级服务");
return ResultVO.fail("fail",null);
}
}
@Service
public class OrderAddServiceImpl implements OrderAddService {
@Autowired
private OrderAddClient orderAddClient;
//当我们创建Feign客户端的降级类并交给Spring管理后 在Spring容器中就会出现两个OrderAddClient对象
//此处会显示编译错误 不用管
@Override
public ResultVO saveOrder(Order order) {
//1. 调⽤ order-add服务进⾏保存
ResultVO vo = orderAddClient.addOrder(order);
//2. 调⽤ orderitem-add 保存订单快照
//3. 调⽤ stock-update 修改商品库存
//4. 调⽤ shopcart-del 删除购物⻋记录
return vo;
}
}
在Feign客户端的方法中,如果不指定参数的传值方式,则默认为body传参,Get请求也不例外;
因此对于url传值如get请求,必须通过@RequestParam注解声明
@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order,String str){
System.out.println("-------------------order-add");
System.out.println(order);
System.out.println(str);
return orderService.saveOrder(order);
}
//1.对⽤POST请求调⽤服务,Feign客户端的⽅法参数默认为body传值(body只能有⼀个值)
//2.如果有多个参数,则需要通过@RequestParam声明参数为请求⾏传值
@FeignClient("order-add")
public interface OrderAddClient {
@PostMapping("order/add")
public ResultVO addOrder(Order order,@RequestParam("str") String str);
//请求行传参
@GetMapping("order/get")
public Order getOrder(@RequestParam("orderId") String orderId);
}
服务故障的雪崩效应:当A服务调用B服务时,由于B服务的故障导致A服务处于阻塞状态,大量的请求可能会导致A服务因资源耗尽而出现故障。
为了解决服务故障的雪崩效应,出现了熔断器模型。
hystrix 已经停更 最新版本 2.2.3.RELEASE
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
feign:
circuitbreaker:
enabled: true
如果服务器的并发压力过大、服务器无法正常响应,则熔断器状态变为open属于正常的情况;但是如果⼀个熔断器⼀直处于open状态、或者说服务器提供者没有访问压⼒的情况下熔断器依然为open状态,说明熔断器的状态就不属于正常情况了。如何了解熔断器的工作状态呢 ?
- 熔断器仪表盘
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency> <dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency> <dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboardartifactId>
dependency>
server:
port: 9999
spring:
application:
name: hystrix-dashboard
hystrix:
dashboard:
proxy-stream-allow-list: "localhost"
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
@Configuration
public class DashBoardConfig {
@Bean
public ServletRegistrationBean getServletRegistrationBean(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean =
new ServletRegistrationBean(streamServlet);
registrationBean.setName("HystrixMetricsStreamServlet");
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
return registrationBean;
}
}
在使用微服务架构开发的项目中,每个服务都有自己的配置文件(application.yml),如果将每个服务的配置文件直接写在对应的服务中,存在以下问题:
Config使用步骤:
1.创建⼀个Git远程仓库,用来存放配置文件
2.搭建分布式配置中心服务器(Spring Cloud Config)Config server 连接到配置文件的Git仓库并注册到eureka
3.修改每个服务Config client,删除application.yml中的所有配置,连接到分布式配置中心
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-serverartifactId>
dependency>
server:
port: 8888
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://gitee.com/qfytao/fmmall-config.git
search-paths: files
username: [email protected]
password: admin123
eureka:
client:
service-url:
defaultZone: http://zhangsan:123456@localhost:8761/eureka
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
spring:
cloud:
config:
uri: http://localhost:8888
name: api-order-submit
label: master