日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringCloud学习笔记(1)- Spring Cloud Alibaba

發(fā)布時(shí)間:2024/1/23 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringCloud学习笔记(1)- Spring Cloud Alibaba 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • SpringCloud學(xué)習(xí)筆記(1)- Spring Cloud Alibaba
  • 服務(wù)治理
    • Nacos 服務(wù)注冊(cè)
    • Nacos 服務(wù)發(fā)現(xiàn)與調(diào)用
    • Ribbon 負(fù)載均衡
    • Sentinel 服務(wù)限流降級(jí)
      • 流控規(guī)則
      • 流控效果
      • 降級(jí)規(guī)則
      • 熱點(diǎn)規(guī)則
      • 授權(quán)規(guī)則
      • 自定義規(guī)則異常返回
    • 整合 RocketMQ
      • 安裝 RocketMQ
      • 安裝 RocketMQ 控制臺(tái)
      • Java 實(shí)現(xiàn)消息發(fā)送
      • Java 實(shí)現(xiàn)消息消費(fèi)
    • Spring Boot 整合 RocketMQ
    • 服務(wù)網(wǎng)關(guān)
      • Gateway 限流
    • 分布式事務(wù)
      • 模擬分布式事務(wù)異常
      • Seata 解決(事務(wù)回滾)

SpringCloud學(xué)習(xí)筆記(1)- Spring Cloud Alibaba

創(chuàng)建父工程

Spring Cloud Alibaba 的環(huán)境在父工程中創(chuàng)建,微服務(wù)的各個(gè)組件作為子工程,繼承父工程的環(huán)境。

Spring Boot —》Spring Cloud —》Spring Cloud Alibaba

pom.xml 中添加。

<dependencyManagement><dependencies><!-- Spring Cloud Hoxton --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR3</version><type>pom</type><scope>import</scope></dependency><!-- Spring Cloud Alibaba --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.1.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies> </dependencyManagement>

服務(wù)治理

服務(wù)注冊(cè) + 服務(wù)發(fā)現(xiàn)

Nacos 服務(wù)注冊(cè)

解壓,啟動(dòng)服務(wù)。

Nacos 搭建成功,接下來注冊(cè)服務(wù)。

在父工程路徑下創(chuàng)建子工程,讓子工程繼承父工程的環(huán)境依賴,pom.xml 中添加 nacos 發(fā)現(xiàn)組件。

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>

application.yml 中配置

spring:cloud:nacos:discovery:# 指定nacos server地址server-addr: localhost:8848application:name: my-nacos

Nacos 服務(wù)發(fā)現(xiàn)與調(diào)用

pom.xml 添加 discovery,完成服務(wù)發(fā)現(xiàn)。

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>

通過 discoveryClient 發(fā)現(xiàn)注冊(cè)到 nacos 中的 provider 服務(wù)。

@RestController public class ConsumerController {@Autowiredprivate DiscoveryClient discoveryClient;@GetMapping("/instances")public List<ServiceInstance> instances(){List<ServiceInstance> provider = discoveryClient.getInstances("provider");return provider;}} @Configuration public class ConsumerConfig {@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}} @RestController public class ConsumerController {@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate RestTemplate restTemplate;@GetMapping("/index")public String index(){List<ServiceInstance> provider = discoveryClient.getInstances("provider");int index = ThreadLocalRandom.current().nextInt(provider.size());String url = provider.get(index).getUri()+"/index";return "consumer隨機(jī)遠(yuǎn)程調(diào)用provier:"+this.restTemplate.getForObject(url, String.class);}}

Ribbon 負(fù)載均衡

@Configuration public class ConsumerConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}} @RestController public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/index")public String index(){return "consumer遠(yuǎn)程調(diào)用provier:"+this.restTemplate.getForObject("http://provider/index", String.class);}}

隨機(jī) (隨機(jī)的算法)

server:port: 8180 provider:ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Nacos 權(quán)重 (基于權(quán)重的算法)

@Slf4j public class NacosWeightedRule extends AbstractLoadBalancerRule {@Autowiredprivate NacosDiscoveryProperties nacosDiscoveryProperties;@Overridepublic void initWithNiwsConfig(IClientConfig iClientConfig) {//讀取配置文件}@Overridepublic Server choose(Object o) {ILoadBalancer loadBalancer = this.getLoadBalancer();BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) loadBalancer;//獲取要請(qǐng)求的微服務(wù)名稱String name = baseLoadBalancer.getName();//獲取服務(wù)發(fā)現(xiàn)的相關(guān)APINamingService namingService = nacosDiscoveryProperties.namingServiceInstance();try {Instance instance = namingService.selectOneHealthyInstance(name);log.info("選擇的實(shí)例是port={},instance={}",instance.getPort(),instance);return new NacosServer(instance);} catch (NacosException e) {e.printStackTrace();return null;}} } server:port: 8180 provider:ribbon:NFLoadBalancerRuleClassName: com.southwind.configuration.NacosWeightedRule

Sentinel 服務(wù)限流降級(jí)

雪崩效應(yīng)

解決方案

1、設(shè)置線程超時(shí)

2、設(shè)置限流

3、熔斷器 Sentinel、Hystrix (類比保險(xiǎn)絲)

  • 降級(jí)
  • 限流
  • 熔斷


1、provider模塊pom.xml 引入依賴

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>

2、application 配置

management:endpoints:web:exposure:include: '*' spring:cloud:sentinel:transport:dashboard: localhost:8080

3、下載 Sentinel 控制臺(tái),解壓,啟動(dòng)。

流控規(guī)則

直接限流

關(guān)聯(lián)限流

鏈路限流

1、pom.xml 添加依賴

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.7.1</version> </dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-web-servlet</artifactId><version>1.7.1</version> </dependency>

2、application.yml

spring:cloud:sentinel:filter:enabled: false

3、寫配置類(讓能關(guān)聯(lián)到Service)

package com.southwind.configuration;import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class FilterConfiguration {@Beanpublic FilterRegistrationBean registrationBean(){FilterRegistrationBean registrationBean = new FilterRegistrationBean();registrationBean.setFilter(new CommonFilter());registrationBean.addUrlPatterns("/*");registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false"); //讓所有鏈路開放出來才能限制registrationBean.setName("sentinelFilter");return registrationBean;} }

4、Service

@Service public class HelloService {@SentinelResource("test")public void test(){System.out.println("test");} }

5、Controller

@GetMapping("/test1") public String test1(){this.helloService.test();return "test1"; }@GetMapping("/test2") public String test2(){this.helloService.test();return "test2"; }

流控效果

快速失敗

直接拋出異常

Warm UP

給系統(tǒng)一個(gè)預(yù)熱的時(shí)間,預(yù)熱時(shí)間段內(nèi)單機(jī)閾值較低,預(yù)熱時(shí)間過后單機(jī)閾值增加,預(yù)熱時(shí)間內(nèi)當(dāng)前的單機(jī)閾值是設(shè)置的閾值的三分之一,預(yù)熱時(shí)間過后單機(jī)閾值恢復(fù)設(shè)置的值。

排隊(duì)等待

當(dāng)請(qǐng)求調(diào)用失敗之后,不會(huì)立即拋出異常,等待下一次調(diào)用,時(shí)間范圍是超時(shí)時(shí)間,在時(shí)間范圍內(nèi)如果能請(qǐng)求成功則不拋出異常,如果請(qǐng)求則拋出異常。

降級(jí)規(guī)則

RT

單個(gè)請(qǐng)求的響應(yīng)時(shí)間超過閾值,則進(jìn)入準(zhǔn)降級(jí)狀態(tài),接下來 1 S 內(nèi)連續(xù) 5 個(gè)請(qǐng)求響應(yīng)時(shí)間均超過閾值,就進(jìn)行降級(jí),持續(xù)時(shí)間為時(shí)間窗口的值。

異常比例

每秒異常數(shù)量占通過量的比例大于閾值,就進(jìn)行降級(jí)處理,持續(xù)時(shí)間為時(shí)間窗口的值。

異常數(shù)

1 分鐘內(nèi)的異常數(shù)超過閾值就進(jìn)行降級(jí)處理,時(shí)間窗口的值要大于 60S,否則剛結(jié)束熔斷又進(jìn)入下一次熔斷了。

熱點(diǎn)規(guī)則

熱點(diǎn)規(guī)則是流控規(guī)則的更細(xì)粒度操作,可以具體到對(duì)某個(gè)熱點(diǎn)參數(shù)的限流,設(shè)置限流之后,如果帶著限流參數(shù)的請(qǐng)求量超過閾值,則進(jìn)行限流,時(shí)間為統(tǒng)計(jì)窗口時(shí)長(zhǎng)。

必須要添加 @SentinelResource,即對(duì)資源進(jìn)行流控。

@GetMapping("/hot") @SentinelResource("hot") public String hot(@RequestParam(value = "num1",required = false) Integer num1,@RequestParam(value = "num2",required = false) Integer num2){return num1+"-"+num2; }

授權(quán)規(guī)則

給指定的資源設(shè)置流控應(yīng)用(追加參數(shù)),可以對(duì)流控應(yīng)用進(jìn)行訪問權(quán)限的設(shè)置,具體就是添加白名單和黑名單。

如何給請(qǐng)求指定流控應(yīng)用,通過實(shí)現(xiàn) RequestOriginParser 接口來完成,代碼如下所示。

package com.southwind.configuration;import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;public class RequestOriginParserDefinition implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest httpServletRequest) {String name = httpServletRequest.getParameter("name");if(StringUtils.isEmpty(name)){throw new RuntimeException("name is null");}return name;} }

要讓 RequestOriginParserDefinition 生效,需要在配置類中進(jìn)行配置。

package com.southwind.configuration;import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;@Configuration public class SentinelConfiguration {@PostConstructpublic void init(){WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());} }

自定義規(guī)則異常返回

創(chuàng)建異常處理類

package com.southwind.handler;import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class ExceptionHandler implements UrlBlockHandler {@Overridepublic void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {httpServletResponse.setContentType("text/html;charset=utf-8");String msg = null;if(e instanceof FlowException){msg = "限流";}else if(e instanceof DegradeException){msg = "降級(jí)";}httpServletResponse.getWriter().write(msg);} }

進(jìn)行配置。

@Configuration public class SentinelConfiguration {@PostConstructpublic void init(){WebCallbackManager.setUrlBlockHandler(new ExceptionHandler());} }

整合 RocketMQ

安裝 RocketMQ

1、傳入 Linux 服務(wù)器

2、解壓縮

unzip rocketmq-all-4.7.1-bin-release.zip

3、啟動(dòng) NameServer

nohup ./bin/mqnamesrv &

4、檢查是否啟動(dòng)成功

netstat -an | grep 9876


5、啟動(dòng) Broker

啟動(dòng)之前需要編輯配置文件,修改 JVM 內(nèi)存設(shè)置,默認(rèn)給的內(nèi)存 4 GB,超過我們的 JVM 了。

cd bin vim runserver.sh

vim runbroker.sh


啟動(dòng) Broker

nohup ./mqbroker -n localhost:9876 &

可以查看日志

tail -f ~/logs/rocketmqlogs/broker.log


啟動(dòng)成功

6、測(cè)試 RocketMQ

消息發(fā)送

cd bin export NAMESRV_ADDR=localhost:9876 ./tools.sh org.apache.rocketmq.example.quickstart.Producer

消息接收

cd bin export NAMESRV_ADDR=localhost:9876 ./tools.sh org.apache.rocketmq.example.quickstart.Consumer

7、關(guān)閉 RocketMQ

cd bin ./mqshutdown broker ./mqshutdown namesrv

安裝 RocketMQ 控制臺(tái)

1、解壓縮,修改配置,打包

mvn clean package -Dmaven.test.skip=true


2、進(jìn)入 target 啟動(dòng) jar

java -jar rocketmq-console-ng-1.0.0.jar


打開瀏覽器訪問 localhost:9877,如果報(bào)錯(cuò)如下:

這是因?yàn)槲覀兊?RocketMQ 安裝在 Linux 中,控制臺(tái)在 windows,Linux 需要開放端口才能訪問,開放 10909 和 9876 端口

firewall-cmd --zone=public --add-port=10909/tcp --permanent firewall-cmd --zone=public --add-port=9876/tcp --permanent systemctl restart firewalld.service firewall-cmd --reload

重新啟動(dòng)控制臺(tái)項(xiàng)目

Java 實(shí)現(xiàn)消息發(fā)送

1、pom.xml 中引入依賴

<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.1.0</version> </dependency>

2、生產(chǎn)消息

package com.southwind;import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message;public class Test {public static void main(String[] args) throws Exception {//創(chuàng)建消息生產(chǎn)者DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");//設(shè)置NameServerproducer.setNamesrvAddr("192.168.248.129:9876");//啟動(dòng)生產(chǎn)者producer.start();//構(gòu)建消息對(duì)象Message message = new Message("myTopic","myTag",("Test MQ").getBytes());//發(fā)送消息SendResult result = producer.send(message, 1000);System.out.println(result);//關(guān)閉生產(chǎn)者producer.shutdown();} }

3、直接運(yùn)行,如果報(bào)錯(cuò) sendDefaultImpl call timeout,可以開放 10911 端口

firewall-cmd --zone=public --add-port=10911/tcp --permanent systemctl restart firewalld.service firewall-cmd --reload

打開 RocketMQ 控制臺(tái),可查看消息。

Java 實(shí)現(xiàn)消息消費(fèi)

package com.southwind.service;import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.message.MessageExt;import java.util.List;@Slf4j public class ConsumerTest {public static void main(String[] args) throws MQClientException {//創(chuàng)建消息消費(fèi)者DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("myconsumer-group");//設(shè)置NameServerconsumer.setNamesrvAddr("192.168.248.129:9876");//指定訂閱的主題和標(biāo)簽consumer.subscribe("myTopic","*");//回調(diào)函數(shù)consumer.registerMessageListener(new MessageListenerConcurrently() {@Overridepublic ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {log.info("Message=>{}",list);return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;}});//啟動(dòng)消費(fèi)者consumer.start();} }

Spring Boot 整合 RocketMQ

provider

1、pom.xml

<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.1.0</version> </dependency> <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client</artifactId><version>4.7.0</version> </dependency>

2、application.yml

rocketmq:name-server: 192.168.248.129:9876producer:group: myprovider

3、Order

package com.southwind.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.util.Date;@Data @AllArgsConstructor @NoArgsConstructor public class Order {private Integer id;private String buyerName;private String buyerTel;private String address;private Date createDate; }

4、Controller

@Autowired private RocketMQTemplate rocketMQTemplate;@GetMapping("/create") public Order create(){Order order = new Order(1,"張三","123123","軟件園",new Date());this.rocketMQTemplate.convertAndSend("myTopic",order);return order; }

consumer

1、pom.xml

<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.1.0</version> </dependency> <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client</artifactId><version>4.7.0</version> </dependency>

2、application.yml

rocketmq:name-server: 192.168.248.129:9876

3、Service

@Slf4j @Service @RocketMQMessageListener(consumerGroup = "myConsumer",topic = "myTopic") public class SmsService implements RocketMQListener<Order> {@Overridepublic void onMessage(Order order) {log.info("新訂單{},發(fā)短信",order);} }

服務(wù)網(wǎng)關(guān)

Spring Cloud Gateway 是基于 Netty,跟 Servlet 不兼容,所以你的工程中不能出現(xiàn) Servlet 的組件 。

1、pom.xml

注意,一定不能出現(xiàn) spring web 的依賴,因?yàn)?Gateway 與 Servlet 不兼容。

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId> </dependency>

2、application.yml

server:port: 8010 spring:application:name: gatewaycloud:gateway:discovery:locator:enabled: trueroutes: - id: provider_route uri: http://localhost:8081 predicates: - Path=/provider/** filters:- StripPrefix=1

上面這種做法其實(shí)沒有用到 nacos ,現(xiàn)在我們讓 gateway 直接去 nacos 中發(fā)現(xiàn)服務(wù),配置更加簡(jiǎn)單了。

1、pom.xml 引入 nacos

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId> </dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>

2、application.yml

server:port: 8010 spring:application:name: gatewaycloud:gateway:discovery:locator:enabled: true

Gateway 限流

基于路由限流

1、pom.xml

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId> </dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency>

2、配置類

package com.southwind.configuration;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;import javax.annotation.PostConstruct; import java.util.*;@Configuration public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}//配置限流的異常處理@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}//配置初始化的限流參數(shù)@PostConstructpublic void initGatewayRules(){Set<GatewayFlowRule> rules = new HashSet<>();rules.add(new GatewayFlowRule("provider_route").setCount(1).setIntervalSec(1));GatewayRuleManager.loadRules(rules);}//初始化限流過濾器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();}//自定義限流異常頁面@PostConstructpublic void initBlockHandlers(){BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {Map map = new HashMap();map.put("code",0);map.put("msg","被限流了");return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromObject(map));}};GatewayCallbackManager.setBlockHandler(blockRequestHandler);} }

3、application.yml

server:port: 8010 spring:application:name: gatewaycloud:gateway:discovery:locator:enabled: trueroutes:- id: provider_routeuri: http://localhost:8081predicates:- Path=/provider/**filters:- StripPrefix=1

基于 API 分組限流

1、修改配置類,添加基于 API 分組限流的方法,修改初始化的限流參數(shù)

package com.southwind.configuration;import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem; import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;import javax.annotation.PostConstruct; import java.util.*;@Configuration public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}//配置限流的異常處理@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}//配置初始化的限流參數(shù)@PostConstructpublic void initGatewayRules(){Set<GatewayFlowRule> rules = new HashSet<>();rules.add(new GatewayFlowRule("provider_api1").setCount(1).setIntervalSec(1));rules.add(new GatewayFlowRule("provider_api2").setCount(1).setIntervalSec(1));GatewayRuleManager.loadRules(rules);}//初始化限流過濾器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();}//自定義限流異常頁面@PostConstructpublic void initBlockHandlers(){BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {Map map = new HashMap();map.put("code",0);map.put("msg","被限流了");return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromObject(map));}};GatewayCallbackManager.setBlockHandler(blockRequestHandler);}//自定義API分組@PostConstructprivate void initCustomizedApis(){Set<ApiDefinition> definitions = new HashSet<>();ApiDefinition api1 = new ApiDefinition("provider_api1").setPredicateItems(new HashSet<ApiPredicateItem>(){{add(new ApiPathPredicateItem().setPattern("/provider/api1/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));}});ApiDefinition api2 = new ApiDefinition("provider_api2").setPredicateItems(new HashSet<ApiPredicateItem>(){{add(new ApiPathPredicateItem().setPattern("/provider/api2/demo1"));}});definitions.add(api1);definitions.add(api2);GatewayApiDefinitionManager.loadApiDefinitions(definitions);} }

2、Controller 添加方法

@GetMapping("/api1/demo1") public String demo1(){return "demo"; }@GetMapping("/api1/demo2") public String demo2(){return "demo"; }@GetMapping("/api2/demo1") public String demo3(){return "demo"; }@GetMapping("/api2/demo2") public String demo4(){return "demo"; }

也可以基于 Nacos 服務(wù)發(fā)現(xiàn)組件進(jìn)行限流

server:port: 8010 spring:application:name: gatewaycloud:gateway:discovery:locator:enabled: true

API 分組代碼修改,改為 discovery 中的服務(wù)名。

ApiDefinition api2 = new ApiDefinition("provider_api2").setPredicateItems(new HashSet<ApiPredicateItem>(){{add(new ApiPathPredicateItem().setPattern("/p1/api2/demo1"));}});

分布式事務(wù)

模擬分布式事務(wù)異常

1、創(chuàng)建兩個(gè)工程 order、pay,pom.xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope> </dependency> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional> </dependency>

2、建兩個(gè)數(shù)據(jù)庫(kù) order、pay,兩個(gè)微服務(wù)分別訪問。

3、分別寫兩個(gè)服務(wù)的 application.yml

server:port: 8010 spring:application:name: orderdatasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456url: jdbc:mysql://localhost:3306/order server:port: 8020 spring:application:name: paydatasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456url: jdbc:mysql://localhost:3306/pay

4、分別寫兩個(gè) Service

package com.southwind.service;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service;@Service public class OrderService {@Autowiredprivate JdbcTemplate jdbcTemplate;public void save(){this.jdbcTemplate.update("insert into orders(username) values ('張三')");} } package com.southwind.service;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service;@Service public class PayService {@Autowiredprivate JdbcTemplate jdbcTemplate;public void save(){this.jdbcTemplate.update("insert into pay(username) values ('張三')");} }

5、控制器 Order 通過 RestTemplate 調(diào)用 Pay 的服務(wù)

package com.southwind.controller;import com.southwind.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;@RestController public class OrderController {@Autowiredprivate OrderService orderService;@Autowiredprivate RestTemplate restTemplate;@GetMapping("/save")public String save(){//訂單this.orderService.save();int i = 10/0;//支付this.restTemplate.getForObject("http://localhost:8020/save",String.class);return "success";} } package com.southwind.controller;import com.southwind.service.PayService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class PayController {@Autowiredprivate PayService payService;@GetMapping("/save")public String save(){this.payService.save();return "success";} }

6、啟動(dòng)類

package com.southwind;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate;@SpringBootApplication public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}@Beanpublic RestTemplate restTemplate(){return new RestTemplate();} } package com.southwind;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class PayApplication {public static void main(String[] args) {SpringApplication.run(PayApplication.class, args);}}

分布式異常模擬結(jié)束,Order 存儲(chǔ)完成之后,出現(xiàn)異常,會(huì)導(dǎo)致 Pay 無法存儲(chǔ),但是 Order 數(shù)據(jù)庫(kù)不會(huì)進(jìn)行回滾。

Seata 解決(事務(wù)回滾)

1、下載

2、解壓,修改兩個(gè)文件

regisry.conf

registry {type = "nacos"nacos {serverAddr = "localhost"namespace = "public"cluster = "default"} }config {type = "nacos"nacos {serverAddr = "localhost"namespace = "public"cluster = "default"} }

nacos-config.txt

3、啟動(dòng) Nacos,運(yùn)行 nacos-config.sh 將 Seata 配置導(dǎo)入 Nacos

進(jìn)入 conf,右鍵 Git Bash Here

cd conf sh nacos-config.sh 127.0.0.1

執(zhí)行成功,刷新 Nacos,配置加入(如下圖)

nacos-config.txt 配置已生效

4、啟動(dòng) Seata Server, JDK 8 以上環(huán)境無法啟動(dòng)

cd bin seata-server.bat -p 8090 -m file


啟動(dòng)成功,Nacos 注冊(cè)成功。

Seata 服務(wù)環(huán)境搭建完畢,接下來去應(yīng)用中添加。

1、初始化數(shù)據(jù)庫(kù),在兩個(gè)數(shù)據(jù)庫(kù)中添加事務(wù)日志記錄表,SQL Seata 已經(jīng)提供。


2、直接在兩個(gè)數(shù)據(jù)庫(kù)運(yùn)行腳本。

CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

3、兩個(gè)工程的 pom.xml 添加 Seata 組件和 Nacos Config 組件。

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><version>2.1.1.RELEASE</version> </dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>

4、給 JDBCTemplate 添加代理數(shù)據(jù)源

package com.southwind;import io.seata.rm.datasource.DataSourceProxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.client.RestTemplate;import javax.sql.DataSource;@SpringBootApplication public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){return new JdbcTemplate(new DataSourceProxy(dataSource));} } package com.southwind;import io.seata.rm.datasource.DataSourceProxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate;import javax.sql.DataSource;@SpringBootApplication public class PayApplication {public static void main(String[] args) {SpringApplication.run(PayApplication.class, args);}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){return new JdbcTemplate(new DataSourceProxy(dataSource));}}

5、將 registry.conf 復(fù)制到兩個(gè)工程的 resources 下。

6、給兩個(gè)工程添加 bootstrap.yml 讀取 Nacos 配置。

spring:application:name: ordercloud:nacos:config:server-addr: localhost:8848namespace: publicgroup: SEATA_GROUPalibaba:seata:tx-service-group: ${spring.application.name} spring:application:name: paycloud:nacos:config:server-addr: localhost:8848namespace: publicgroup: SEATA_GROUPalibaba:seata:tx-service-group: ${spring.application.name}

tx-service-group 需要和 Nacos 配置中的名稱一致。

7、在 Order 調(diào)用 Pay 處添加注解 @GlobalTransactional

package com.southwind.controller;import com.southwind.service.OrderService; import io.seata.spring.annotation.GlobalTransactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;@RestController public class OrderController {@Autowiredprivate OrderService orderService;@Autowiredprivate RestTemplate restTemplate;@GetMapping("/save")@GlobalTransactionalpublic String save(){//訂單this.orderService.save();int i = 10/0;//支付this.restTemplate.getForObject("http://localhost:8020/save",String.class);return "success";} }

【視頻參考】https://www.bilibili.com/video/BV1Mt4y1i7JW
【源碼參考】https://github.com/monkeyhlj/spring-study

總結(jié)

以上是生活随笔為你收集整理的SpringCloud学习笔记(1)- Spring Cloud Alibaba的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。