很多小伙伴让我整理下有关SpringCloud和SpringCloudAlibaba的知识点,通过3天的收集和整理,冰河整理出这份4万字的SpringCloud与SpringCloudAlibaba学习笔记!!java
文章已收录到:git
https://github.com/sunshinelyz/technology-binghegithub
https://gitee.com/binghe001/technology-bingheweb
ap 高可用 分布式容错spring
<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-eureka-client</artifactId> </dependency> eureka: instance: hostname: eureka7003.com #eureka服务端的实例名称 instance-id: payment8001 prefer-ip-address: true client: register-with-eureka: false #false表示不向注册中心注册本身。 fetch-registry: false #false表示本身端就是注册中心,个人职责就是维护服务实例,并不须要去检索服务 service-url: #集群指向其它eureka #defaultZone: http://eureka7002.com:7002/eureka/ #单机就是7001本身 defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ #server: #关闭自我保护机制,保证不可用服务被及时踢除 #enable-self-preservation: false #eviction-interval-timer-in-ms: 2000
@EnableEurekaServer @EnableDiscoveryClient @LoadBalanced public RestTemplate getTemp() { return new RestTemplate(); }
cp 强一致 分布式容错apache
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.1</version> </dependency> spring: application: name: cloud-zoo-consumer-order cloud: zookeeper: connect-string: 192.168.10.58:2181 @SpringBootApplication @EnableDiscoveryClient
cp 强一致 分布式容错json
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> spring: application: name: consul-payment-provider cloud: consul: host: 192.168.10.58 port: 8500 discovery: service-name: ${spring.application.name} @SpringBootApplication @EnableDiscoveryClient
@Configuration public class Myrule { @Bean public IRule initRule() { return new RandomRule(); } }
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = Myrule.class)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient @EnableFeignClients
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") //提供方服务名 public interface Service { @GetMapping(value = "/payment/get/{id}") Response<Payment> getPaymentById(@PathVariable("id") Long id); }
@GetMapping(value = "/payment/get/{id}") public Response<Payment> getPaymentById(@PathVariable("id") Long id) { Payment payment = paymentService.getPaymentById(id); if (payment != null) { return Result.success(200, "查询成功,serverPort: " + serverPort, payment); } else { return Result.success(444, "没有对应记录,查询ID: " + id, null); } }
ribbon: #指的是创建链接所用的时间,适用于网络情况正常的状况下,两端链接所用的时间 ReadTimeout: 5000 #指的是创建链接后从服务器读取到可用资源所用的时间 ConnectTimeout: 5000
@Configuration public class FeignLogConfig { @Bean public Logger.Level getLevel() { return Logger.Level.FULL; } }
logging: level: ml.ytooo.feignservice.Service: debug
主方法bootstrap
@EnableCircuitBreaker
须要降级处理的程序springboot
其中bash
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOut_Handler", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public String paymentInfo_TimeOut(Integer id) { int time = 5; try { TimeUnit.MILLISECONDS.sleep(time * 1000); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池: " + Thread.currentThread().getName() + " paymentInfo_TimeOut,id: " + id + "\t" + "O(∩_∩)O哈哈~" + " 耗时(秒): " + time; } public String paymentInfo_TimeOut_Handler(Integer id) { return "线程池: " + Thread.currentThread().getName() + " paymentInfo_TimeOut_Handler,id: " + id + "\t" + "o(╥﹏╥)o"; }
配置 defaultFallback 的走本身的降级方法,未配置的走 默认@DefaultProperties 指定的降级方法
@RestController @Slf4j @DefaultProperties(defaultFallback = "globle",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500") }) public class Controller { @HystrixCommand @GetMapping("/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id) { String result = feignService.paymentInfo_TimeOut(id); log.info("*****result: " + result); return result; } public String globle() { return "全局"; } }
@Service public class FeignServiceImpl implements FeignService { @Override public String paymentInfo_OK(Integer id) { return "降级 -- paymentInfo_OK"; } @Override public String paymentInfo_TimeOut(Integer id) { return "降级 -- paymentInfo_TimeOut"; } }
@FeignClient(value = "CLOUD-PROVIDER-HYSTYRIX-PAYMENT",fallback = FeignServiceImpl.class)
配置服务的熔断:
一下配置在 10s 内 ,10次请求有60% 失败,则熔断
HystrixProperty 配置位于 HystrixCommandProperties.class 类中
//=====服务熔断 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { // @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少百分百后跳闸 }) public String paymentCircuitBreaker(@PathVariable("id") Integer id) { if(id < 0) { throw new RuntimeException("******id 不能负数"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName()+"\t"+"调用成功,流水号: " + serialNumber; } public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) //熔断后降级方法 { return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~ id: " +id; }
效果: 当连续使用 -100 请求时, 返回 "id 不能负数", 使用100请求也返回 "id 不能负数" ,继续连续使用 100请求, 服务慢慢恢复
使用 springcloud 阿里巴巴 sentinel 替代
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
spring: application: name: cloud-gateaway-gateaway cloud: gateway: discovery: locator: enabled: true routes: - id: payment_get # uri: http://127.0.0.1:8001 #单一节点 uri : lb://CLOUD-PAYMENT-SERVICE /#启用 注册中心集群 predicates: - Path=/payment/get/**
spring: application: name: cloud-gateaway-gateaway cloud: gateway: discovery: locator: enabled: true
断言是判断转发请求的条件
predicates: - After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
public static void main(String[] args) { ZonedDateTime now = ZonedDateTime.now(); System.out.println(now); } // 2020-08-24T14:23:57.171+08:00[Asia/Shanghai]
predicates: - Cookie=name,ytooo # key,value
predicates: - Header=name,ytooo # key,value
filters: - AddRequestParamter=rowid,1024
自定义全局过滤器
@Component @Slf4j public class GatewayLogFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("=====================进入全局过滤器====================="); String name = exchange.getRequest().getQueryParams().getFirst("name"); if (null == name) { exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
3.启动类使配置生效
@SpringBootApplication @EnableEurekaClient @EnableConfigServer public class ConfigMain3344 { public static void main(String[] args) { SpringApplication.run(ConfigMain3344.class, args); } }
spring: application: name: cloud-config-center cloud: config: server: git: uri: https://github.com/sunshinelyz/cloud-config search-paths: - cloud-config label: master
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency>
spring: application: name: cloud-condig-client cloud: config: label: master # 分支 name: config # 配置文件名称 profile: dev # 版本 uri: http://127.0.0.1:3344 # config服务端地址
不建议使用
使用消息总线触发服务端的 bus/refresh 端点,刷新全部客户端config配置
客户端,服务端都须要实现Springcloud Config功能
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
# 配置消息队列 rabbitmq: host: 192.168.10.58 port: 5672 username: ytooo password: ytooo
# 配置bus暴露端点 management: endpoints: web: exposure: include: "bus-refresh"
server: port: 3344 spring: application: name: cloud-config-center cloud: config: server: git: uri: https://github.com/sunshinelyz/cloud-config search-paths: - cloud-config label: master # 配置消息队列 rabbitmq: host: 192.168.10.58 port: 5672 username: ytooo password: ytooo eureka: instance: prefer-ip-address: true instance-id: cloud-config-center-3344 client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://eureka7001.com:7001/eureka/ #,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ # 配置bus暴露端点 management: endpoints: web: exposure: include: "bus-refresh"
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
# 配置消息队列 rabbitmq: host: 192.168.10.58 port: 5672 username: ytooo password: ytooo
# 配置暴露端点 management: endpoints: web: exposure: include: "*"
@RestController @RefreshScope public class Controller { @Value("${config.info}") private String configInfo; @GetMapping(value = "/test") public String test() { return configInfo; } }
POST 请求config服务端 http://127.0.0.1:3344/actuator/bus-refresh
刷新成功
POST 请求config服务端 http://127.0.0.1:3344/actuator/bus-refresh/{destination}
destination: 注册中心服务名称:端口号
🌰: http://127.0.0.1:3344/actuator/bus-refresh/cloud-condig-client:3366
消息驱动,统一各类消息中间件中的差别,提供统一简单的调用方式,屏蔽消息中间件具体调用实现
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency>
spring: application: name: cloud-stream-provider cloud: stream: binders: # 在此处配置要绑定的rabbitmq的服务信息; defaultRabbit: # 表示定义的名称,用于于binding整合 type: rabbit # 消息组件类型 environment: # 设置rabbitmq的相关的环境配置 spring: rabbitmq: host: 192.168.10.58 port: 5672 username: ytooo password: ytooo bindings: # 服务的整合处理 output: # 这个名字是一个通道的名称 destination: studyExchange # 表示要使用的Exchange名称定义 content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain” binder: defaultRabbit # 设置要绑定的消息服务的具体设置
@EnableBinding(Source.class) //定义消息推送管道 public class MsgProviderImpl implements MsgProvider { }
@Autowired private MessageChannel out; //定义消息发送管道
Message<String> message = MessageBuilder.withPayload(msg).build(); out.send(message);
spring: application: name: cloud-stream-rabbitmq-consumer cloud: stream: binders: # 在此处配置要绑定的rabbitmq的服务信息; defaultRabbit: # 表示定义的名称,用于于binding整合 type: rabbit # 消息组件类型 environment: # 设置rabbitmq的相关的环境配置 spring: rabbitmq: host: 192.168.10.58 port: 5672 username: ytooo password: ytooo bindings: # 服务的整合处理 input: # 这个名字是一个通道的名称 destination: studyExchange # 表示要使用的Exchange名称定义 需与提供方相同 content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain” binder: defaultRabbit # 设置要绑定的消息服务的具体设置
@EnableBinding(Sink.class) public class ReceiveMsgImpl implements ReceiveMsg { }
@StreamListener(Sink.INPUT) public void receive(Message<String> message) { System.out.println("客服端8803收到消息: " + message.getPayload()); }
bindings: # 服务的整合处理 input: # 这个名字是一个通道的名称 destination: studyExchange # 表示要使用的Exchange名称定义 content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain” binder: defaultRabbit # 设置要绑定的消息服务的具体设置 group: ytooo # 配置接收方所在组
当不配置分组时,重启服务,不会自动获取以前未消费的服务
反之,配置了分组,启动时,自动获取以前未消费的消息
在服务中加上依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
修改application.yml配置文件,添加如下内容
spring: zipkin: base-url: http://localhost:9411 sleuth: sampler: probability: 1 # 采样率值介于0~1之间,1表示所有采集
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
spring: application: name: cloudalibaba-nacos-consumer-order cloud: nacos: discovery: server-addr: 192.168.10.58:8848
@EnableDiscoveryClient
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-config</artifactId> </dependency>
spring: application: name: cloudalibaba-nacos-config-cclient cloud: nacos: discovery: server-addr: 192.168.10.58:8848 config: server-addr: 192.168.10.58:8848 file-extension: yaml profiles: active: dev
@RestController @RefreshScope public class Controller {
在 Nacos Spring Cloud 中,dataId 的完整格式以下:
prefix−{prefix}-prefix−{spring.profiles.active}.${file-extension}
本实例中文件名称应为: cloudalibaba-nacos-config-cclient-dev.yaml
Nacos 使用3层来隔离服务
yml 中配置分组信息group ,和命名空间 namespace
spring: application: name: cloudalibaba-nacos-config-cclient cloud: nacos: discovery: server-addr: 192.168.10.58:8848 config: server-addr: 192.168.10.58:8848 file-extension: yaml group: dev namespace: a2438b02-01e1-4a3c-959c-600d93183d22 # 使用命名空间ID
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <!-- Sentinel持久化 --> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: 192.168.10.58:8848 sentinel: transport: dashboard: 192.168.10.58:8888 # sentinel dashboard 地址
配置降级方法: 此方法只针对页面中配置的指定 降级限流热点等方法
@GetMapping(value = "/hot") @SentinelResource(value = "hot", blockHandler = "deal_hot") public String hot(String p1, String p2) { return "========================== 热点经过 =========================="; } public String deal_hot(String p1, String p2, BlockException e) { return "========================== 热点降级 =========================="; }
好了,今天就到这儿吧,我是冰河,你们有啥问题能够在下方留言,也能够加我微信:sun_shine_lyz,我拉你进群,一块儿交流技术,一块儿进阶,一块儿牛逼~~