Repository: alibaba/spring-cloud-alibaba
Branch: 2025.1.x
Commit: b85e7efead6b
Files: 748
Total size: 2.1 MB
Directory structure:
gitextract_av4r5gmy/
├── .circleci/
│ └── config.yml
├── .codecov.yml
├── .editorconfig
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ ├── feature_request.md
│ │ └── question.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── dependbot.yml
│ ├── labels.yml
│ └── workflows/
│ ├── github-packages-release.yml
│ ├── integration-test.yml
│ ├── issue-command.yml
│ ├── md-link-check.yml
│ └── stale.yml
├── .gitignore
├── .licenscheckconfig.yaml
├── .mvn/
│ ├── jvm.config
│ └── wrapper/
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README-zh.md
├── README.md
├── Roadmap-zh.md
├── Roadmap.md
├── eclipse/
│ ├── checkstyle-suppressions.xml
│ ├── eclipse-code-formatter.xml
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.jdt.ui.prefs
├── mvnw
├── mvnw.cmd
├── pom.xml
├── spring-cloud-alibaba-coverage/
│ └── pom.xml
├── spring-cloud-alibaba-dependencies/
│ └── pom.xml
├── spring-cloud-alibaba-examples/
│ ├── integrated-example/
│ │ ├── config-init/
│ │ │ ├── config/
│ │ │ │ ├── datasource-config.yaml
│ │ │ │ ├── integrated-account.yaml
│ │ │ │ ├── integrated-consumer.yaml
│ │ │ │ ├── integrated-gateway.yaml
│ │ │ │ ├── integrated-order.yaml
│ │ │ │ ├── integrated-provider.yaml
│ │ │ │ └── integrated-storage.yaml
│ │ │ ├── rocketmq/
│ │ │ │ └── broker.conf
│ │ │ ├── scripts/
│ │ │ │ └── nacos-config-quick.sh
│ │ │ └── sql/
│ │ │ └── init.sql
│ │ ├── docker-compose/
│ │ │ ├── docker-compose-env.yml
│ │ │ └── docker-compose-service.yml
│ │ ├── docs/
│ │ │ ├── en/
│ │ │ │ ├── docker-compose-deployment.md
│ │ │ │ ├── kubernetes-deployment.md
│ │ │ │ ├── local-deployment.md
│ │ │ │ └── readme.md
│ │ │ └── zh/
│ │ │ ├── docker-compose-deploy-zh.md
│ │ │ ├── kubernetes-deployment-zh.md
│ │ │ ├── local-deployment-zh.md
│ │ │ └── readme-zh.md
│ │ ├── helm-chart/
│ │ │ ├── Chart.yaml
│ │ │ ├── templates/
│ │ │ │ ├── integrated-account.yaml
│ │ │ │ ├── integrated-frontend.yaml
│ │ │ │ ├── integrated-gateway.yaml
│ │ │ │ ├── integrated-mysql.yaml
│ │ │ │ ├── integrated-nacos-mysql.yaml
│ │ │ │ ├── integrated-nacos-stand.yaml
│ │ │ │ ├── integrated-order.yaml
│ │ │ │ ├── integrated-praise-consumer.yaml
│ │ │ │ ├── integrated-praise-provider.yaml
│ │ │ │ ├── integrated-rocketmq.yaml
│ │ │ │ ├── integrated-seata.yaml
│ │ │ │ └── integrated-storage.yaml
│ │ │ └── values.yaml
│ │ ├── integrated-account/
│ │ │ ├── Dockerfile
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── integration/
│ │ │ │ └── account/
│ │ │ │ ├── AccountServiceApplication.java
│ │ │ │ ├── controller/
│ │ │ │ │ └── AccountController.java
│ │ │ │ ├── dto/
│ │ │ │ │ └── AccountDTO.java
│ │ │ │ ├── mapper/
│ │ │ │ │ └── AccountMapper.java
│ │ │ │ └── service/
│ │ │ │ ├── AccountService.java
│ │ │ │ └── impl/
│ │ │ │ └── AccountServiceImpl.java
│ │ │ └── resources/
│ │ │ └── application.yaml
│ │ ├── integrated-common/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ └── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── integration/
│ │ │ └── common/
│ │ │ ├── BusinessException.java
│ │ │ ├── IResult.java
│ │ │ ├── Result.java
│ │ │ └── ResultEnum.java
│ │ ├── integrated-frontend/
│ │ │ ├── Dockerfile
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── integration/
│ │ │ │ └── frontend/
│ │ │ │ ├── FrontendApplication.java
│ │ │ │ └── controller/
│ │ │ │ └── IntegrationController.java
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ ├── order.html
│ │ │ ├── rocketmq.html
│ │ │ └── sentinel.html
│ │ ├── integrated-gateway/
│ │ │ ├── Dockerfile
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── integration/
│ │ │ │ └── gateway/
│ │ │ │ ├── GatewayApplication.java
│ │ │ │ └── config/
│ │ │ │ └── GatewayConfig.java
│ │ │ └── resources/
│ │ │ └── application.yaml
│ │ ├── integrated-order/
│ │ │ ├── Dockerfile
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── integration/
│ │ │ │ └── order/
│ │ │ │ ├── OrderServiceApplication.java
│ │ │ │ ├── controller/
│ │ │ │ │ └── OrderController.java
│ │ │ │ ├── entity/
│ │ │ │ │ └── Order.java
│ │ │ │ ├── feign/
│ │ │ │ │ ├── AccountServiceFeignClient.java
│ │ │ │ │ ├── StorageServiceFeignClient.java
│ │ │ │ │ └── dto/
│ │ │ │ │ ├── AccountDTO.java
│ │ │ │ │ └── StorageDTO.java
│ │ │ │ ├── mapper/
│ │ │ │ │ └── OrderMapper.java
│ │ │ │ └── service/
│ │ │ │ ├── OrderService.java
│ │ │ │ └── impl/
│ │ │ │ └── OrderServiceImpl.java
│ │ │ └── resources/
│ │ │ └── application.yaml
│ │ ├── integrated-praise-consumer/
│ │ │ ├── Dockerfile
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── integration/
│ │ │ │ └── consumer/
│ │ │ │ ├── PraiseConsumerApplication.java
│ │ │ │ ├── controller/
│ │ │ │ │ └── PraiseController.java
│ │ │ │ ├── listener/
│ │ │ │ │ └── ListenerAutoConfiguration.java
│ │ │ │ ├── mapper/
│ │ │ │ │ └── PraiseMapper.java
│ │ │ │ ├── message/
│ │ │ │ │ └── PraiseMessage.java
│ │ │ │ └── service/
│ │ │ │ ├── PraiseService.java
│ │ │ │ └── impl/
│ │ │ │ └── PraiseServiceImpl.java
│ │ │ └── resources/
│ │ │ └── application.yaml
│ │ ├── integrated-praise-provider/
│ │ │ ├── Dockerfile
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── integration/
│ │ │ │ └── provider/
│ │ │ │ ├── PraiseProviderApplication.java
│ │ │ │ ├── controller/
│ │ │ │ │ └── PraiseController.java
│ │ │ │ └── message/
│ │ │ │ └── PraiseMessage.java
│ │ │ └── resources/
│ │ │ └── application.yaml
│ │ └── integrated-storage/
│ │ ├── Dockerfile
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── integration/
│ │ │ └── storage/
│ │ │ ├── StorageServiceApplication.java
│ │ │ ├── controller/
│ │ │ │ └── StorageController.java
│ │ │ ├── dto/
│ │ │ │ └── StorageDTO.java
│ │ │ ├── mapper/
│ │ │ │ └── StorageMapper.java
│ │ │ └── service/
│ │ │ ├── StorageService.java
│ │ │ └── impl/
│ │ │ └── StorageServiceImpl.java
│ │ └── resources/
│ │ └── application.yaml
│ ├── nacos-example/
│ │ ├── nacos-config-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── NacosConfigApplication.java
│ │ │ │ ├── example/
│ │ │ │ │ ├── BeanAutoRefreshConfigExample.java
│ │ │ │ │ ├── ConfigListenerExample.java
│ │ │ │ │ ├── DockingInterfaceExample.java
│ │ │ │ │ └── ValueAnnotationExample.java
│ │ │ │ └── model/
│ │ │ │ └── NacosConfigInfo.java
│ │ │ └── resources/
│ │ │ └── application.yaml
│ │ ├── nacos-discovery-example/
│ │ │ ├── nacos-discovery-consumer-example/
│ │ │ │ ├── pom.xml
│ │ │ │ ├── scripts/
│ │ │ │ │ ├── error.sh
│ │ │ │ │ ├── feign-defaultmethod-error.sh
│ │ │ │ │ ├── feign-error.sh
│ │ │ │ │ ├── index.sh
│ │ │ │ │ └── sleep.sh
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ ├── ConsumerApplication.java
│ │ │ │ │ ├── TestController.java
│ │ │ │ │ ├── configuration/
│ │ │ │ │ │ ├── FeignConfiguration.java
│ │ │ │ │ │ ├── RestTemplateConfiguration.java
│ │ │ │ │ │ └── UrlCleaner.java
│ │ │ │ │ └── feign/
│ │ │ │ │ ├── EchoClient.java
│ │ │ │ │ └── EchoClientFallback.java
│ │ │ │ └── resources/
│ │ │ │ ├── application.properties
│ │ │ │ ├── degraderule.json
│ │ │ │ └── flowrule.json
│ │ │ ├── nacos-discovery-consumer-sclb-example/
│ │ │ │ ├── pom.xml
│ │ │ │ ├── scripts/
│ │ │ │ │ ├── error.sh
│ │ │ │ │ ├── feign-defaultmethod-error.sh
│ │ │ │ │ ├── feign-error.sh
│ │ │ │ │ ├── index.sh
│ │ │ │ │ ├── resttemplate.sh
│ │ │ │ │ └── sleep.sh
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ ├── ConsumerSCLBApplication.java
│ │ │ │ │ ├── RandomLoadBalancer.java
│ │ │ │ │ ├── TestController.java
│ │ │ │ │ ├── config/
│ │ │ │ │ │ ├── FeignConfiguration.java
│ │ │ │ │ │ ├── MyLoadBalancerConfiguration.java
│ │ │ │ │ │ ├── MySCLBConfiguration.java
│ │ │ │ │ │ ├── RestTemplateConfiguration.java
│ │ │ │ │ │ └── UrlCleaner.java
│ │ │ │ │ └── feign/
│ │ │ │ │ ├── EchoClient.java
│ │ │ │ │ └── EchoClientFallback.java
│ │ │ │ └── resources/
│ │ │ │ ├── application.properties
│ │ │ │ ├── degraderule.json
│ │ │ │ └── flowrule.json
│ │ │ ├── nacos-discovery-provider-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ ├── EchoController.java
│ │ │ │ │ └── ProviderApplication.java
│ │ │ │ └── resources/
│ │ │ │ └── application.properties
│ │ │ ├── nacos-discovery-spring-cloud-config-client-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ ├── GetConfigController.java
│ │ │ │ │ └── SpringCloudConfigClientApplication.java
│ │ │ │ └── resources/
│ │ │ │ └── application.yml
│ │ │ ├── nacos-discovery-spring-cloud-config-server-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ └── SpringCloudConfigServerApplication.java
│ │ │ │ └── resources/
│ │ │ │ └── application.yml
│ │ │ ├── nacos-reactivediscovery-consumer-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ ├── ConsumerReactiveApplication.java
│ │ │ │ │ ├── MyController.java
│ │ │ │ │ └── WebClientConfiguration.java
│ │ │ │ └── resources/
│ │ │ │ └── application.properties
│ │ │ └── pom.xml
│ │ ├── nacos-gateway-example/
│ │ │ ├── nacos-gateway-discovery-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ └── GatewayApplication.java
│ │ │ │ └── resources/
│ │ │ │ └── application.properties
│ │ │ ├── nacos-gateway-provider-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ ├── EchoController.java
│ │ │ │ │ └── ProviderApplication.java
│ │ │ │ └── resources/
│ │ │ │ └── application.properties
│ │ │ └── pom.xml
│ │ ├── readme-zh.md
│ │ └── readme.md
│ ├── pom.xml
│ ├── rocketmq-example/
│ │ ├── readme-zh.md
│ │ ├── readme.md
│ │ ├── rocketmq-broadcast-example/
│ │ │ ├── rocketmq-broadcast-consumer1-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ └── broadcast/
│ │ │ │ │ └── RocketMQBroadcastConsumer1Application.java
│ │ │ │ └── resources/
│ │ │ │ └── application.yml
│ │ │ ├── rocketmq-broadcast-consumer2-example/
│ │ │ │ ├── pom.xml
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ └── broadcast/
│ │ │ │ │ └── RocketMQBroadcastConsumer2Application.java
│ │ │ │ └── resources/
│ │ │ │ └── application.yml
│ │ │ └── rocketmq-broadcast-producer-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ └── broadcast/
│ │ │ │ └── RocketMQBroadcastProducerApplication.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── rocketmq-comprehensive-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── RocketMQComprehensiveApplication.java
│ │ │ │ └── User.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── rocketmq-delay-consume-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ └── delay/
│ │ │ │ └── RocketMQDelayConsumeApplication.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── rocketmq-example-common/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ └── common/
│ │ │ │ └── SimpleMsg.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── rocketmq-orderly-consume-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ └── orderly/
│ │ │ │ ├── OrderlyMessageQueueSelector.java
│ │ │ │ └── RocketMQOrderlyConsumeApplication.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── rocketmq-pollable-consume-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ └── pollable/
│ │ │ │ └── RocketMQPollableConsumeApplication.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── rocketmq-sql-consume-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ └── sql/
│ │ │ │ └── RocketMQSqlConsumeApplication.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── rocketmq-tx-example/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── examples/
│ │ │ └── tx/
│ │ │ ├── RocketMQTxApplication.java
│ │ │ └── TransactionListenerImpl.java
│ │ └── resources/
│ │ └── application.yml
│ ├── seata-example/
│ │ ├── account-service/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── AccountApplication.java
│ │ │ │ ├── AccountController.java
│ │ │ │ └── DatabaseConfiguration.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── all.sql
│ │ ├── business-service/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── BusinessApplication.java
│ │ │ │ ├── HomeController.java
│ │ │ │ └── Order.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── order-service/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── DatabaseConfiguration.java
│ │ │ │ ├── Order.java
│ │ │ │ ├── OrderApplication.java
│ │ │ │ └── OrderController.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ ├── readme-zh.md
│ │ ├── readme.md
│ │ └── storage-service/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── examples/
│ │ │ ├── StorageApplication.java
│ │ │ ├── config/
│ │ │ │ └── DatabaseConfiguration.java
│ │ │ └── controller/
│ │ │ └── StorageController.java
│ │ └── resources/
│ │ └── application.yml
│ ├── sentinel-example/
│ │ ├── README-zh.md
│ │ ├── README.md
│ │ ├── sentinel-circuitbreaker-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── FeignCircuitBreakerApplication.java
│ │ │ │ ├── controller/
│ │ │ │ │ ├── ApiController.java
│ │ │ │ │ └── TestController.java
│ │ │ │ └── feign/
│ │ │ │ ├── OrderClient.java
│ │ │ │ ├── OrderClientFallBack.java
│ │ │ │ ├── UserClient.java
│ │ │ │ └── UserClientFallBack.java
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ └── sentinel-circuitbreaker-rules.yml
│ │ ├── sentinel-core-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── ExceptionUtil.java
│ │ │ │ ├── JsonFlowRuleListConverter.java
│ │ │ │ ├── SentinelCoreApplication.java
│ │ │ │ ├── TestController.java
│ │ │ │ └── WebMvcConfiguration.java
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ ├── authority.json
│ │ │ ├── degraderule.json
│ │ │ ├── flowrule.json
│ │ │ ├── flowrule.xml
│ │ │ ├── param-flow.json
│ │ │ ├── system.json
│ │ │ └── templates/
│ │ │ └── errorPage.html
│ │ ├── sentinel-openfeign-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── OpenFeignApplication.java
│ │ │ │ ├── configuration/
│ │ │ │ │ ├── EchoServiceFallbackFactory.java
│ │ │ │ │ ├── HttpbinClient.java
│ │ │ │ │ ├── HttpbinClientFallback.java
│ │ │ │ │ └── SentinelRulesConfiguration.java
│ │ │ │ └── controller/
│ │ │ │ └── TestController.java
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ ├── degraderule.json
│ │ │ └── flowrule.json
│ │ ├── sentinel-resttemplate-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── alibaba/
│ │ │ │ │ └── cloud/
│ │ │ │ │ └── examples/
│ │ │ │ │ ├── RestTemplateApplication.java
│ │ │ │ │ ├── configuration/
│ │ │ │ │ │ ├── RestTemplateConfiguration.java
│ │ │ │ │ │ └── SentinelRulesConfiguration.java
│ │ │ │ │ └── controller/
│ │ │ │ │ └── TestController.java
│ │ │ │ └── resources/
│ │ │ │ ├── application.yml
│ │ │ │ ├── degraderule.json
│ │ │ │ └── flowrule.json
│ │ │ └── test/
│ │ │ └── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── examples/
│ │ │ └── RestTemplateApplicationTest.java
│ │ ├── sentinel-spring-cloud-gateway-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── examples/
│ │ │ │ ├── MySCGConfiguration.java
│ │ │ │ ├── RulesWebFluxController.java
│ │ │ │ └── SentinelSpringCloudGatewayApplication.java
│ │ │ └── resources/
│ │ │ ├── api.json
│ │ │ ├── application.yaml
│ │ │ └── gateway.json
│ │ └── sentinel-webflux-example/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── examples/
│ │ │ ├── MyConfiguration.java
│ │ │ ├── SentinelWebFluxApplication.java
│ │ │ └── SentinelWebFluxController.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── flowrule.json
│ ├── spring-cloud-alibaba-sidecar-examples/
│ │ ├── node-service.js
│ │ ├── readme-zh.md
│ │ ├── readme.md
│ │ ├── spring-cloud-alibaba-sidecar-consul-example/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── sidecar/
│ │ │ │ └── DemoApplication.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── spring-cloud-alibaba-sidecar-nacos-example/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── sidecar/
│ │ │ └── DemoApplication.java
│ │ └── resources/
│ │ └── application.yml
│ ├── spring-cloud-bus-rocketmq-example/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── examples/
│ │ │ └── rocketmq/
│ │ │ ├── RocketMQBusApplication.java
│ │ │ ├── User.java
│ │ │ └── UserRemoteApplicationEvent.java
│ │ └── resources/
│ │ └── application.properties
│ └── spring-cloud-scheduling-example/
│ ├── README-en.md
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── examples/
│ │ └── schedule/
│ │ ├── ScheduleApplication.java
│ │ └── job/
│ │ └── SimpleJob.java
│ └── resources/
│ ├── application-schedulerx.yaml
│ ├── application-shedlock.yaml
│ └── application.yaml
├── spring-cloud-alibaba-starters/
│ ├── pom.xml
│ ├── spring-alibaba-nacos-config/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── nacos/
│ │ │ │ ├── NacosConfigAutoConfiguration.java
│ │ │ │ ├── NacosConfigEnabledCondition.java
│ │ │ │ ├── NacosConfigManager.java
│ │ │ │ ├── NacosConfigProperties.java
│ │ │ │ ├── NacosPropertiesPrefixProvider.java
│ │ │ │ ├── NacosPropertiesPrefixer.java
│ │ │ │ ├── NacosPropertySourceRepository.java
│ │ │ │ ├── annotation/
│ │ │ │ │ ├── AbstractConfigChangeListener.java
│ │ │ │ │ ├── CustomDateDeserializer.java
│ │ │ │ │ ├── JsonUtils.java
│ │ │ │ │ ├── NacosAnnotationProcessor.java
│ │ │ │ │ ├── NacosConfig.java
│ │ │ │ │ ├── NacosConfigKeysListener.java
│ │ │ │ │ ├── NacosConfigListener.java
│ │ │ │ │ ├── NacosConfigRefreshableListener.java
│ │ │ │ │ ├── NacosPropertiesKeyListener.java
│ │ │ │ │ ├── ObjectUtils.java
│ │ │ │ │ ├── PropertiesUtils.java
│ │ │ │ │ ├── ScaYamlConfigChangeParser.java
│ │ │ │ │ └── TargetRefreshable.java
│ │ │ │ ├── client/
│ │ │ │ │ ├── NacosPropertySource.java
│ │ │ │ │ └── NacosPropertySourceBuilder.java
│ │ │ │ ├── configdata/
│ │ │ │ │ ├── ConfigPreference.java
│ │ │ │ │ ├── NacosConfigDataLoadProperties.java
│ │ │ │ │ ├── NacosConfigDataLoader.java
│ │ │ │ │ ├── NacosConfigDataLocationResolver.java
│ │ │ │ │ └── NacosConfigDataResource.java
│ │ │ │ ├── constants/
│ │ │ │ │ └── Constants.java
│ │ │ │ ├── diagnostics/
│ │ │ │ │ └── analyzer/
│ │ │ │ │ ├── NacosConnectionFailureAnalyzer.java
│ │ │ │ │ └── NacosConnectionFailureException.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── NacosConfigEndpoint.java
│ │ │ │ │ ├── NacosConfigEndpointAutoConfiguration.java
│ │ │ │ │ └── NacosConfigHealthIndicator.java
│ │ │ │ ├── parser/
│ │ │ │ │ ├── AbstractPropertySourceLoader.java
│ │ │ │ │ ├── NacosByteArrayResource.java
│ │ │ │ │ ├── NacosDataParserHandler.java
│ │ │ │ │ ├── NacosJsonPropertySourceLoader.java
│ │ │ │ │ └── NacosXmlPropertySourceLoader.java
│ │ │ │ ├── proxy/
│ │ │ │ │ └── druid/
│ │ │ │ │ ├── NacosDruidConfigFilter.java
│ │ │ │ │ └── NacosDruidFilterConfiguration.java
│ │ │ │ ├── refresh/
│ │ │ │ │ ├── NacosConfigRefreshEvent.java
│ │ │ │ │ ├── NacosContextRefresher.java
│ │ │ │ │ ├── NacosPropertySourceRefreshListener.java
│ │ │ │ │ ├── NacosRefreshHistory.java
│ │ │ │ │ └── NacosSnapshotConfigManager.java
│ │ │ │ └── utils/
│ │ │ │ ├── NacosConfigUtils.java
│ │ │ │ ├── PropertySourcesUtils.java
│ │ │ │ └── StringUtils.java
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ ├── additional-spring-configuration-metadata.json
│ │ │ ├── native-image/
│ │ │ │ ├── reflect-config.json
│ │ │ │ └── resource-config.json
│ │ │ ├── services/
│ │ │ │ └── com.alibaba.nacos.api.config.listener.ConfigChangeParser
│ │ │ ├── spring/
│ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ │ └── spring.factories
│ │ └── test/
│ │ └── java/
│ │ ├── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── nacos/
│ │ │ └── annotation/
│ │ │ └── NacosPropertiesKeyListenerTest.java
│ │ └── com.alibaba.cloud.nacos/
│ │ ├── NacosConfigPropertiesTest.java
│ │ ├── configdata/
│ │ │ └── NacosConfigDataLocationResolverTest.java
│ │ └── endpoint/
│ │ └── NacosConfigEndpointTests.java
│ ├── spring-cloud-alibaba-commons/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── commons/
│ │ ├── context/
│ │ │ └── support/
│ │ │ └── PropertySourcesUtils.java
│ │ ├── io/
│ │ │ ├── Charsets.java
│ │ │ ├── FileUtils.java
│ │ │ ├── IOUtils.java
│ │ │ └── StringBuilderWriter.java
│ │ └── lang/
│ │ └── StringUtils.java
│ ├── spring-cloud-alibaba-sentinel-datasource/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── sentinel/
│ │ │ │ └── datasource/
│ │ │ │ ├── RuleType.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── AbstractDataSourceProperties.java
│ │ │ │ │ ├── ApolloDataSourceProperties.java
│ │ │ │ │ ├── ConsulDataSourceProperties.java
│ │ │ │ │ ├── DataSourcePropertiesConfiguration.java
│ │ │ │ │ ├── FileDataSourceProperties.java
│ │ │ │ │ ├── NacosDataSourceProperties.java
│ │ │ │ │ ├── RedisDataSourceProperties.java
│ │ │ │ │ └── ZookeeperDataSourceProperties.java
│ │ │ │ ├── converter/
│ │ │ │ │ ├── JsonConverter.java
│ │ │ │ │ ├── SentinelConverter.java
│ │ │ │ │ └── XmlConverter.java
│ │ │ │ └── factorybean/
│ │ │ │ ├── ApolloDataSourceFactoryBean.java
│ │ │ │ ├── ConsulDataSourceFactoryBean.java
│ │ │ │ ├── FileRefreshableDataSourceFactoryBean.java
│ │ │ │ ├── NacosDataSourceFactoryBean.java
│ │ │ │ ├── RedisDataSourceFactoryBean.java
│ │ │ │ └── ZookeeperDataSourceFactoryBean.java
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ └── sentinel-datasource.properties
│ │ └── test/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── sentinel/
│ │ │ └── datasource/
│ │ │ ├── ApolloDataSourceFactoryBeanTests.java
│ │ │ ├── DataSourcePropertiesConfigurationTests.java
│ │ │ ├── DataSourcePropertiesTests.java
│ │ │ ├── FileRefreshableDataSourceFactoryBeanTests.java
│ │ │ ├── NacosDataSourceFactoryBeanTests.java
│ │ │ ├── NacosDataSourcePropertiesTests.java
│ │ │ ├── RuleTypeTests.java
│ │ │ ├── SentinelConverterTests.java
│ │ │ └── ZookeeperDataSourceFactoryBeanTests.java
│ │ └── resources/
│ │ ├── flowrule-errorcontent.json
│ │ ├── flowrule-errorformat.json
│ │ ├── flowrule.json
│ │ └── flowrule.xml
│ ├── spring-cloud-alibaba-sentinel-gateway/
│ │ ├── README.md
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── sentinel/
│ │ │ │ └── gateway/
│ │ │ │ ├── ConfigConstants.java
│ │ │ │ ├── FallbackProperties.java
│ │ │ │ ├── GatewayEnvironmentPostProcessor.java
│ │ │ │ ├── SentinelGatewayAutoConfiguration.java
│ │ │ │ └── scg/
│ │ │ │ ├── SentinelGatewayProperties.java
│ │ │ │ └── SentinelSCGAutoConfiguration.java
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ ├── spring/
│ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ │ └── spring.factories
│ │ └── test/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── sentinel/
│ │ │ └── gateway/
│ │ │ ├── ConfigConstantsTest.java
│ │ │ ├── FallbackPropertiesTest.java
│ │ │ ├── GatewayEnvironmentPostProcessorTest.java
│ │ │ ├── SentinelGatewayAutoConfigurationTest.java
│ │ │ └── scg/
│ │ │ ├── SentinelGatewayPropertiesTest.java
│ │ │ └── SentinelSCGAutoConfigurationTest.java
│ │ └── resources/
│ │ ├── apidefinition.json
│ │ ├── apidefinition.xml
│ │ ├── gatewayflowrule.json
│ │ └── gatewayflowrule.xml
│ ├── spring-cloud-circuitbreaker-sentinel/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── circuitbreaker/
│ │ │ │ └── sentinel/
│ │ │ │ ├── ReactiveSentinelCircuitBreaker.java
│ │ │ │ ├── ReactiveSentinelCircuitBreakerAutoConfiguration.java
│ │ │ │ ├── ReactiveSentinelCircuitBreakerFactory.java
│ │ │ │ ├── SentinelCircuitBreaker.java
│ │ │ │ ├── SentinelCircuitBreakerAutoConfiguration.java
│ │ │ │ ├── SentinelCircuitBreakerFactory.java
│ │ │ │ ├── SentinelConfigBuilder.java
│ │ │ │ └── feign/
│ │ │ │ ├── CircuitBreakerRuleChangeListener.java
│ │ │ │ ├── FeignClientCircuitNameResolver.java
│ │ │ │ ├── SentinelFeignClientAutoConfiguration.java
│ │ │ │ └── SentinelFeignClientProperties.java
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ ├── additional-spring-configuration-metadata.json
│ │ │ └── spring/
│ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── circuitbreaker/
│ │ └── sentinel/
│ │ ├── ReactiveSentinelCircuitBreakerIntegrationTest.java
│ │ ├── ReactiveSentinelCircuitBreakerTest.java
│ │ ├── SentinelCircuitBreakerIntegrationTest.java
│ │ ├── SentinelCircuitBreakerTest.java
│ │ └── feign/
│ │ └── FeignClientCircuitBreakerRuleIntegrationTest.java
│ ├── spring-cloud-starter-alibaba-nacos-config/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── nacos/
│ │ │ │ ├── NacosConfigSpringCloudAutoConfiguration.java
│ │ │ │ ├── SpringCloudNacosPropertiesPrefixProvider.java
│ │ │ │ ├── client/
│ │ │ │ │ └── NacosPropertySourceLocator.java
│ │ │ │ ├── configdata/
│ │ │ │ │ ├── NacosConfigDataMissingEnvironmentPostProcessor.java
│ │ │ │ │ └── NacosConfigRefreshEventListener.java
│ │ │ │ └── refresh/
│ │ │ │ ├── RefreshBehavior.java
│ │ │ │ ├── SmartConfigurationPropertiesRebinder.java
│ │ │ │ └── condition/
│ │ │ │ ├── ConditionalOnNonDefaultBehavior.java
│ │ │ │ └── NonDefaultBehaviorCondition.java
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ ├── additional-spring-configuration-metadata.json
│ │ │ ├── services/
│ │ │ │ └── com.alibaba.cloud.nacos.NacosPropertiesPrefixProvider
│ │ │ ├── spring/
│ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ │ └── spring.factories
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── nacos/
│ │ ├── SmartConfigurationPropertiesRebinderIntegrationTest.java
│ │ └── configdata/
│ │ └── NacosConfigDataMissingEnvironmentPostProcessorTest.java
│ ├── spring-cloud-starter-alibaba-nacos-discovery/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── nacos/
│ │ │ │ ├── ConditionalOnNacosDiscoveryEnabled.java
│ │ │ │ ├── NacosDiscoveryProperties.java
│ │ │ │ ├── NacosServiceAutoConfiguration.java
│ │ │ │ ├── NacosServiceInstance.java
│ │ │ │ ├── NacosServiceManager.java
│ │ │ │ ├── balancer/
│ │ │ │ │ └── NacosBalancer.java
│ │ │ │ ├── discovery/
│ │ │ │ │ ├── NacosDiscoveryAutoConfiguration.java
│ │ │ │ │ ├── NacosDiscoveryClient.java
│ │ │ │ │ ├── NacosDiscoveryClientConfiguration.java
│ │ │ │ │ ├── NacosDiscoveryHeartBeatConfiguration.java
│ │ │ │ │ ├── NacosDiscoveryHeartBeatPublisher.java
│ │ │ │ │ ├── NacosServiceDiscovery.java
│ │ │ │ │ ├── NacosWatch.java
│ │ │ │ │ ├── ServiceCache.java
│ │ │ │ │ ├── actuate/
│ │ │ │ │ │ └── health/
│ │ │ │ │ │ └── NacosDiscoveryHealthIndicator.java
│ │ │ │ │ ├── configclient/
│ │ │ │ │ │ ├── NacosConfigServerAutoConfiguration.java
│ │ │ │ │ │ └── NacosDiscoveryClientConfigServiceBootstrapConfiguration.java
│ │ │ │ │ └── reactive/
│ │ │ │ │ ├── NacosReactiveDiscoveryClient.java
│ │ │ │ │ └── NacosReactiveDiscoveryClientConfiguration.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── NacosDiscoveryEndpoint.java
│ │ │ │ │ └── NacosDiscoveryEndpointAutoConfiguration.java
│ │ │ │ ├── event/
│ │ │ │ │ └── NacosDiscoveryInfoChangedEvent.java
│ │ │ │ ├── loadbalancer/
│ │ │ │ │ ├── ConditionalOnLoadBalancerNacos.java
│ │ │ │ │ ├── DefaultLoadBalancerAlgorithm.java
│ │ │ │ │ ├── LoadBalancerAlgorithm.java
│ │ │ │ │ ├── LoadBalancerNacosAutoConfiguration.java
│ │ │ │ │ ├── NacosLoadBalancer.java
│ │ │ │ │ ├── NacosLoadBalancerClientConfiguration.java
│ │ │ │ │ └── ServiceInstanceFilter.java
│ │ │ │ ├── registry/
│ │ │ │ │ ├── NacosAutoServiceRegistration.java
│ │ │ │ │ ├── NacosGracefulShutdownDelegate.java
│ │ │ │ │ ├── NacosRegistration.java
│ │ │ │ │ ├── NacosRegistrationCustomizer.java
│ │ │ │ │ ├── NacosServiceRegistry.java
│ │ │ │ │ └── NacosServiceRegistryAutoConfiguration.java
│ │ │ │ └── util/
│ │ │ │ ├── InetIPv6Utils.java
│ │ │ │ └── UtilIPv6AutoConfiguration.java
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ ├── additional-spring-configuration-metadata.json
│ │ │ ├── native-image/
│ │ │ │ ├── reflect-config.json
│ │ │ │ └── resource-config.json
│ │ │ ├── spring/
│ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ │ └── spring.factories
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── nacos/
│ │ ├── NacosDiscoveryClientTests.java
│ │ ├── NacosDiscoveryPropertiesServerAddressBothLevelTests.java
│ │ ├── NacosDiscoveryPropertiesServerAddressTopLevelTests.java
│ │ ├── discovery/
│ │ │ ├── NacosDiscoveryAutoConfigurationTests.java
│ │ │ ├── NacosDiscoveryClientConfigurationTest.java
│ │ │ ├── NacosDiscoveryHeartBeatConfigurationTest.java
│ │ │ ├── NacosDiscoveryLoadBalancerConfigurationTest.java
│ │ │ ├── NacosServiceDiscoveryTest.java
│ │ │ └── reactive/
│ │ │ ├── NacosReactiveDiscoveryClientConfigurationTests.java
│ │ │ └── NacosReactiveDiscoveryClientTests.java
│ │ ├── registry/
│ │ │ ├── MockNamingService.java
│ │ │ ├── NacosAutoServiceRegistrationIpNetworkInterfaceTests.java
│ │ │ ├── NacosAutoServiceRegistrationIpTests.java
│ │ │ ├── NacosAutoServiceRegistrationManagementPortTests.java
│ │ │ ├── NacosAutoServiceRegistrationPortTests.java
│ │ │ ├── NacosAutoServiceRegistrationTests.java
│ │ │ ├── NacosGracefulShutdownDelegateTests.java
│ │ │ └── NacosRegistrationCustomizerTest.java
│ │ └── test/
│ │ ├── CommonTestConfig.java
│ │ └── NacosMockTest.java
│ ├── spring-cloud-starter-alibaba-schedulerx/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── scheduling/
│ │ │ │ ├── SchedulingConstants.java
│ │ │ │ ├── schedulerx/
│ │ │ │ │ ├── JobProperty.java
│ │ │ │ │ ├── SchedulerxAutoConfigure.java
│ │ │ │ │ ├── SchedulerxConfigurations.java
│ │ │ │ │ ├── SchedulerxProperties.java
│ │ │ │ │ ├── constants/
│ │ │ │ │ │ └── SchedulerxConstants.java
│ │ │ │ │ ├── service/
│ │ │ │ │ │ ├── JobSyncService.java
│ │ │ │ │ │ └── ScheduledJobSyncConfigurer.java
│ │ │ │ │ └── util/
│ │ │ │ │ └── CronExpression.java
│ │ │ │ └── shedlock/
│ │ │ │ └── ShedLockAutoConfigure.java
│ │ │ └── resources/
│ │ │ ├── META-INF/
│ │ │ │ ├── spring/
│ │ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ │ │ └── spring.factories
│ │ │ └── shedlock/
│ │ │ └── schema/
│ │ │ └── schema-mysql.sql
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── scheduling/
│ │ └── schedulerx/
│ │ └── util/
│ │ └── CronExpressionTest.java
│ ├── spring-cloud-starter-alibaba-seata/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── seata/
│ │ │ ├── feign/
│ │ │ │ ├── SeataFeignBuilderBeanPostProcessor.java
│ │ │ │ ├── SeataFeignClientAutoConfiguration.java
│ │ │ │ └── SeataFeignRequestInterceptor.java
│ │ │ ├── rest/
│ │ │ │ ├── SeataRestTemplateAutoConfiguration.java
│ │ │ │ ├── SeataRestTemplateInterceptor.java
│ │ │ │ └── SeataRestTemplateInterceptorAfterPropertiesSet.java
│ │ │ ├── web/
│ │ │ │ ├── SeataHandlerInterceptor.java
│ │ │ │ └── SeataHandlerInterceptorConfiguration.java
│ │ │ ├── webclient/
│ │ │ │ ├── SeataWebClientAutoConfiguration.java
│ │ │ │ ├── SeataWebClientBuilderCustomizer.java
│ │ │ │ └── SeataWebClientFilter.java
│ │ │ └── webflux/
│ │ │ ├── SeataWebFilter.java
│ │ │ └── SeataWebfluxAutoConfiguration.java
│ │ └── resources/
│ │ └── META-INF/
│ │ ├── native-image/
│ │ │ ├── com.alibaba.cloud/
│ │ │ │ └── spring-cloud-starter-alibaba-seata/
│ │ │ │ └── native-image.properties
│ │ │ ├── proxy-config.json
│ │ │ ├── reflect-config.json
│ │ │ └── resource-config.json
│ │ └── spring/
│ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ ├── spring-cloud-starter-alibaba-sentinel/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── sentinel/
│ │ │ │ ├── SentinelConstants.java
│ │ │ │ ├── SentinelProperties.java
│ │ │ │ ├── SentinelWebAutoConfiguration.java
│ │ │ │ ├── SentinelWebFluxAutoConfiguration.java
│ │ │ │ ├── SentinelWebMvcConfigurer.java
│ │ │ │ ├── annotation/
│ │ │ │ │ └── SentinelRestTemplate.java
│ │ │ │ ├── aot/
│ │ │ │ │ └── hint/
│ │ │ │ │ └── SentinelProtectInterceptorHints.java
│ │ │ │ ├── custom/
│ │ │ │ │ ├── BlockClassRegistry.java
│ │ │ │ │ ├── SentinelAutoConfiguration.java
│ │ │ │ │ ├── SentinelBeanPostProcessor.java
│ │ │ │ │ ├── SentinelDataSourceHandler.java
│ │ │ │ │ ├── SentinelProtectInterceptor.java
│ │ │ │ │ └── context/
│ │ │ │ │ └── SentinelApplicationContextInitializer.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── SentinelEndpoint.java
│ │ │ │ │ ├── SentinelEndpointAutoConfiguration.java
│ │ │ │ │ └── SentinelHealthIndicator.java
│ │ │ │ ├── feign/
│ │ │ │ │ ├── SentinelContractHolder.java
│ │ │ │ │ ├── SentinelFeign.java
│ │ │ │ │ ├── SentinelFeignAutoConfiguration.java
│ │ │ │ │ └── SentinelInvocationHandler.java
│ │ │ │ └── rest/
│ │ │ │ └── SentinelClientHttpResponse.java
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ ├── additional-spring-configuration-metadata.json
│ │ │ ├── native-image/
│ │ │ │ ├── reflect-config.json
│ │ │ │ └── resource-config.json
│ │ │ ├── spring/
│ │ │ │ ├── aot.factories
│ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ │ └── spring.factories
│ │ └── test/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── sentinel/
│ │ │ ├── ContextIdSentinelFeignTests.java
│ │ │ ├── SentinelAutoConfigurationTests.java
│ │ │ ├── SentinelBeanAutowiredTests.java
│ │ │ ├── SentinelDataSourceTests.java
│ │ │ ├── SentinelFallbackSupportFactoryBeanTests.java
│ │ │ ├── SentinelFeignLazilyTests.java
│ │ │ ├── SentinelFeignTests.java
│ │ │ ├── SentinelRestTemplateTests.java
│ │ │ ├── TestConverter.java
│ │ │ ├── aot/
│ │ │ │ └── hint/
│ │ │ │ └── SentinelProtectInterceptorHintsTest.java
│ │ │ ├── custom/
│ │ │ │ └── SentinelDataSourceHandlerTests.java
│ │ │ └── endpoint/
│ │ │ └── SentinelHealthIndicatorTests.java
│ │ └── resources/
│ │ ├── authority.json
│ │ ├── degraderule.json
│ │ ├── flowrule.json
│ │ ├── param-flow.json
│ │ └── system.json
│ ├── spring-cloud-starter-alibaba-sidecar/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── sidecar/
│ │ │ ├── CustomHealthCheckHandler.java
│ │ │ ├── SidecarAutoConfiguration.java
│ │ │ ├── SidecarDiscoveryClient.java
│ │ │ ├── SidecarHealthChecker.java
│ │ │ ├── SidecarHealthIndicator.java
│ │ │ ├── SidecarInstanceInfo.java
│ │ │ ├── SidecarProperties.java
│ │ │ ├── consul/
│ │ │ │ ├── SidecarConsulAutoConfiguration.java
│ │ │ │ ├── SidecarConsulAutoRegistration.java
│ │ │ │ └── SidecarConsulDiscoveryClient.java
│ │ │ └── nacos/
│ │ │ ├── SidecarNacosAutoConfiguration.java
│ │ │ ├── SidecarNacosDiscoveryClient.java
│ │ │ └── SidecarNacosDiscoveryProperties.java
│ │ └── resources/
│ │ └── META-INF/
│ │ └── spring/
│ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ ├── spring-cloud-starter-bus-rocketmq/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── bus/
│ │ │ └── rocketmq/
│ │ │ ├── autoconfigurate/
│ │ │ │ └── RocketMQBusAutoConfiguration.java
│ │ │ └── env/
│ │ │ └── RocketMQBusEnvironmentPostProcessor.java
│ │ └── resources/
│ │ └── META-INF/
│ │ ├── spring/
│ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ └── spring.factories
│ └── spring-cloud-starter-stream-rocketmq/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── stream/
│ │ │ └── binder/
│ │ │ └── rocketmq/
│ │ │ ├── RocketMQMessageChannelBinder.java
│ │ │ ├── actuator/
│ │ │ │ └── RocketMQBinderHealthIndicator.java
│ │ │ ├── aot/
│ │ │ │ └── hint/
│ │ │ │ ├── RocketMQConsumerPropertiesHints.java
│ │ │ │ └── RocketMQSpecificPropertiesProviderHints.java
│ │ │ ├── autoconfigurate/
│ │ │ │ ├── ExtendedBindingHandlerMappingsProviderConfiguration.java
│ │ │ │ └── RocketMQBinderAutoConfiguration.java
│ │ │ ├── constant/
│ │ │ │ └── RocketMQConst.java
│ │ │ ├── convert/
│ │ │ │ └── RocketMQMessageConverter.java
│ │ │ ├── custom/
│ │ │ │ ├── RocketMQBeanContainerCache.java
│ │ │ │ └── RocketMQConfigBeanPostProcessor.java
│ │ │ ├── extend/
│ │ │ │ └── ErrorAcknowledgeHandler.java
│ │ │ ├── integration/
│ │ │ │ ├── inbound/
│ │ │ │ │ ├── RocketMQConsumerFactory.java
│ │ │ │ │ ├── RocketMQInboundChannelAdapter.java
│ │ │ │ │ └── pull/
│ │ │ │ │ ├── DefaultErrorAcknowledgeHandler.java
│ │ │ │ │ ├── RocketMQAckCallback.java
│ │ │ │ │ └── RocketMQMessageSource.java
│ │ │ │ └── outbound/
│ │ │ │ ├── RocketMQProduceFactory.java
│ │ │ │ └── RocketMQProducerMessageHandler.java
│ │ │ ├── metrics/
│ │ │ │ ├── Instrumentation.java
│ │ │ │ └── InstrumentationManager.java
│ │ │ ├── properties/
│ │ │ │ ├── RocketMQBinderConfigurationProperties.java
│ │ │ │ ├── RocketMQCommonProperties.java
│ │ │ │ ├── RocketMQConsumerProperties.java
│ │ │ │ ├── RocketMQExtendedBindingProperties.java
│ │ │ │ ├── RocketMQProducerProperties.java
│ │ │ │ └── RocketMQSpecificPropertiesProvider.java
│ │ │ ├── provisioning/
│ │ │ │ ├── RocketMQTopicProvisioner.java
│ │ │ │ └── selector/
│ │ │ │ └── PartitionMessageQueueSelector.java
│ │ │ ├── support/
│ │ │ │ ├── AbstractRocketMQHeaderMapper.java
│ │ │ │ ├── JacksonRocketMQHeaderMapper.java
│ │ │ │ ├── RocketMQHeaderMapper.java
│ │ │ │ └── RocketMQMessageConverterSupport.java
│ │ │ └── utils/
│ │ │ └── RocketMQUtils.java
│ │ └── resources/
│ │ └── META-INF/
│ │ ├── native-image/
│ │ │ ├── com.alibaba.cloud/
│ │ │ │ └── spring-cloud-starter-stream-rocketmq/
│ │ │ │ └── native-image.properties
│ │ │ └── reflect-config.json
│ │ ├── spring/
│ │ │ ├── aot.factories
│ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ └── spring.binders
│ └── test/
│ └── java/
│ └── com/
│ └── alibaba/
│ └── cloud/
│ └── stream/
│ └── binder/
│ └── rocketmq/
│ ├── RocketMQAutoConfigurationTests.java
│ ├── RocketMQMessageChannelBinderTest.java
│ ├── RocketMQMessageConverterSupportTest.java
│ ├── TestConsumerDestination.java
│ └── aot/
│ └── hint/
│ ├── RocketMQConsumerPropertiesHintsTests.java
│ └── RocketMQSpecificPropertiesProviderHintsTests.java
└── spring-cloud-alibaba-tests/
├── nacos-tests/
│ ├── nacos-config-test/
│ │ └── src/
│ │ └── test/
│ │ └── resources/
│ │ └── docker/
│ │ └── nacos-compose-test.yml
│ ├── nacos-discovery-test/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── tests/
│ │ │ └── nacos/
│ │ │ └── discovery/
│ │ │ └── NacosDiscoveryTestApp.java
│ │ └── test/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── tests/
│ │ │ └── nacos/
│ │ │ └── discovery/
│ │ │ └── NacosDiscoveryTest.java
│ │ └── resources/
│ │ ├── application-service-1.yml
│ │ ├── application-service-2.yml
│ │ ├── docker/
│ │ │ └── nacos-compose-test.yml
│ │ └── nacos/
│ │ └── nacos-config-refresh.yml
│ └── pom.xml
├── pom.xml
├── rocketmq-tests/
│ ├── pom.xml
│ └── rocketmq-stream-test/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── stream/
│ │ └── binder/
│ │ └── rocketmq/
│ │ └── RocketmqStreamApplication.java
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── stream/
│ │ └── binder/
│ │ └── rocketmq/
│ │ ├── RocketMQAutoConfigurationTests.java
│ │ ├── RocketmqProduceAndConsumerTests.java
│ │ └── fixture/
│ │ └── RocketmqBinderProcessor.java
│ └── resources/
│ └── docker/
│ ├── data/
│ │ └── broker/
│ │ └── conf/
│ │ └── broker.conf
│ ├── data1/
│ │ └── broker/
│ │ └── conf/
│ │ └── broker.conf
│ └── rocket-compose-test.yml
├── sentinel-tests/
│ ├── pom.xml
│ ├── sentinel-degrade-test/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── alibaba/
│ │ │ │ └── cloud/
│ │ │ │ └── tests/
│ │ │ │ └── sentinel/
│ │ │ │ └── degrade/
│ │ │ │ └── SentinelDegradeTestApp.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── cloud/
│ │ └── tests/
│ │ └── sentinel/
│ │ └── degrade/
│ │ └── SentinelDegradeTestAppTest.java
│ └── sentinel-flowcontrol-test/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── cloud/
│ │ │ └── tests/
│ │ │ └── sentinel/
│ │ │ └── degrade/
│ │ │ ├── SentinelFlowControlTestApp.java
│ │ │ └── Util.java
│ │ └── resources/
│ │ └── application.yml
│ └── test/
│ └── java/
│ └── com/
│ └── alibaba/
│ └── cloud/
│ └── tests/
│ └── sentinel/
│ └── degrade/
│ └── SentinelFlowControlTestAppTest.java
└── spring-cloud-alibaba-test-support/
├── pom.xml
└── src/
└── main/
├── java/
│ └── com/
│ └── alibaba/
│ └── cloud/
│ └── testsupport/
│ ├── Constant.java
│ ├── ContainerStarter.java
│ ├── Func.java
│ ├── HasDockerAndItEnabled.java
│ ├── HasDockerAndItEnabledCondition.java
│ ├── InetUtil.java
│ ├── SpringCloudAlibaba.java
│ ├── SpringCloudAlibabaExtension.java
│ ├── TestExtend.java
│ ├── TestTimeoutExtension.java
│ └── Tester.java
└── resources/
└── rocketmq/
└── conf/
└── broker.conf
================================================
FILE CONTENTS
================================================
================================================
FILE: .circleci/config.yml
================================================
version: 2
jobs:
build:
docker:
- image: springcloud/pipeline-base
user: appuser
environment:
_JAVA_OPTIONS: "-Xms1024m -Xmx2048m"
TERM: dumb
branches:
ignore:
- gh-pages # list of branches to ignore
resource_class: medium
steps:
- checkout
- restore_cache:
key: sc-alibaba-{{ .Branch }}
- run:
name: "Download dependencies"
command: ./mvnw -Pspring -U --fail-never dependency:go-offline || true
- save_cache:
key: sc-alibaba-{{ .Branch }}
paths:
- ~/.m2
- run:
name: "Running build"
command: ./mvnw clean install -U -nsu --batch-mode -Dmaven.test.redirectTestOutputToFile=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -Dgpg.skip
- run:
name: "Aggregate test results"
when: always
command: |
mkdir -p ~/junit/
find . -type f -regex ".*/target/.*-reports/.*" -exec cp {} ~/junit/ \;
bash <(curl -s https://codecov.io/bash)
- store_artifacts:
path: ~/junit/
destination: artifacts
- store_test_results:
path: ~/junit/
destination: testartifacts
================================================
FILE: .codecov.yml
================================================
coverage:
status:
project: off
patch: off
================================================
FILE: .editorconfig
================================================
root = true
[*.java]
indent_style = tab
indent_size = 4
continuation_indent_size = 8
[*.groovy]
indent_style = tab
indent_size = 4
continuation_indent_size = 8
[*.xml]
indent_style = tab
indent_size = 4
continuation_indent_size = 8
[*.yml]
indent_style = space
indent_size = 2
[*.yaml]
indent_style = space
indent_size = 2
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
我们鼓励使用英文,如果不能直接使用,可以使用翻译软件,您仍旧可以保留中文原文。另外请按照如下要求提交相关信息节省社区维护同学的理解成本,否则该讨论极有可能直接被忽视或关闭。
We recommend using English. If you are non-native English speaker, you can use the translation software. We recommend using English. If you are non-native English speaker, you can use the translation software. In addition, please submit relevant information according to the following requirements to save the understanding cost of community maintenances, otherwise the discussion is very likely to be ignored or closed directly.
**Which Component**
eg. Nacos Discovery, Sentinel
**Describe the bug**
A clear and concise description of what the bug is.
**Simplest demo**
The URL of the simplest demo to reproduce the problem.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
e.g. MacOS 、Java8 、 Version 0.2.1.RELEASE
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
我们鼓励使用英文,如果不能直接使用,可以使用翻译软件,您仍旧可以保留中文原文。另外请按照如下要求提交相关信息节省社区维护同学的理解成本,否则该讨论极有可能直接被忽视或关闭。
We recommend using English. If you are non-native English speaker, you can use the translation software. In addition, please submit relevant information according to the following requirements to save the understanding cost of community maintenances, otherwise the discussion is very likely to be ignored or closed directly.
**Which Component**
eg. Nacos Discovery, Sentinel
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question
about: how to ask a valid question
title: ''
labels: ''
assignees: ''
---
我们鼓励使用英文,如果不能直接使用,可以使用翻译软件,您仍旧可以保留中文原文。另外请按照如下要求提交相关信息节省社区维护同学的理解成本,否则该讨论极有可能直接被忽视或关闭。
We recommend using English. If you are non-native English speaker, you can use the translation software. We recommend using English. If you are non-native English speaker, you can use the translation software. In addition, please submit relevant information according to the following requirements to save the understanding cost of community maintenances, otherwise the discussion is very likely to be ignored or closed directly.
**Which Component**
eg. Nacos Discovery, Sentinel
**Describe what problem you have encountered**
A clear and concise description of what you want to do.
**Describe what information you have read**
eg. I have read the reference doc of Sentinel
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
### Describe what this PR does / why we need it
### Does this pull request fix one issue?
### Describe how you did it
### Describe how to verify it
### Special notes for reviews
================================================
FILE: .github/dependbot.yml
================================================
# `dependabot.yml` file with
# maven version update.
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
open-pull-requests-limit: 20
# Ignore major version updates
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]
schedule:
interval: "weekly"
day: "monday"
time: "03:00"
timezone: "US/Eastern"
================================================
FILE: .github/labels.yml
================================================
area:
- 'ai'
- 'ci'
- 'nacos'
- 'sentinel'
- 'rocketmq'
- 'community'
- 'example'
- 'seata'
- 'openSergo'
- 'spring cloud'
- 'testing'
kind:
- 'bug'
- 'chore'
- 'discussion'
- 'documention'
- 'question'
- 'refactor'
- 'invalid'
- 'enhancement'
================================================
FILE: .github/workflows/github-packages-release.yml
================================================
name: GitHub Packages Release
on:
push:
branches:
- 2023.x
- 2025.0.x
- 2025.1.x
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt'
- name: Dependencies Cache
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: install dependencies
run: mvn clean -B install -U package -pl '!spring-cloud-alibaba-coverage' -DskipTests
- name: cat ~/.m2/settings.xml
run: |
cat ~/.m2/settings.xml
- name: Deploy to GitHub Package Maven
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
echo "Project version: $VERSION"
if [[ "$VERSION" != *"-SNAPSHOT" ]]; then
echo "Not a snapshot version. Skipping deployment."
exit 0
fi
mvn clean -B deploy -pl . -DskipTests
cd $GITHUB_WORKSPACE/spring-cloud-alibaba-dependencies
mvn clean -B deploy -DskipTests
cd $GITHUB_WORKSPACE/spring-cloud-alibaba-starters
mvn clean -B deploy -DskipTests
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Delete snapshots from the Maven local repository
run: find ~/.m2/repository -type d -name '*-SNAPSHOT' -print -exec rm -r {} +
================================================
FILE: .github/workflows/integration-test.yml
================================================
name: Integration Testing
on:
push:
branches:
- 2023.x
- 2025.0.x
- 2025.1.x
pull_request:
branches:
- 2023.x
- 2025.0.x
- 2025.1.x
jobs:
deploy-docker-image:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
integration-testing:
name: Integration Testing
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt'
- name: Dependencies Cache
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Compile & Checkstyle
run: mvn clean -B compile
- name: install dependencies
run: mvn clean -B install -U package -pl '!spring-cloud-alibaba-coverage' -DskipTests
- name: Testing
run: ./mvnw verify -B -Dmaven.test.skip=false
# run: mvn clean -Dit.enabled=true test
- name: Delete snapshots from the Maven local repository
run: find ~/.m2/repository -type d -name '*-SNAPSHOT' -print -exec rm -r {} +
================================================
FILE: .github/workflows/issue-command.yml
================================================
name: Issue and PR comment commands
permissions: {}
on:
issue_comment:
types:
- created
- edited
jobs:
execute:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: jpmcb/prow-github-actions@f4d01dd4b13f289014c23fe5a19878a2479cb35b # v1.1.3
with:
prow-commands: '/assign
/unassign
/area
/kind
/priority
/remove
/close
/reopen
/lock
/milestone
/hold
/cc
/uncc'
github-token: "${{ secrets.GITHUB_TOKEN }}"
================================================
FILE: .github/workflows/md-link-check.yml
================================================
name: 'Link Checker'
# **What it does**: Renders the content of every page and check all internal links.
# **Why we have it**: To make sure all links connect correctly.
# **Who does it impact**: Docs content.
on:
workflow_dispatch:
push:
# branches: [master, 'release/**']
paths:
- '**/*.md'
- '**/link-check.yml'
pull_request:
branches: [2023.x, 2025.0.x, 2025.1.x, "release/**"]
paths:
- '**/*.md'
- '**/link-check.yml'
permissions:
contents: read
# Needed for the 'trilom/file-changes-action' action
pull-requests: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
check-links:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get script
run: |
wget https://raw.githubusercontent.com/xuruidong/markdown-link-checker/main/link_checker.py
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Link check (critical, all files)
run: |
# python link_checker.py ./ --enable-external --ignore "http://apisix.iresty.com" "https://www.upyun.com" "https://github.com/apache/apisix/actions/workflows/build.yml/badge.svg" "https://httpbin.org/" "https://en.wikipedia.org/wiki/Cache"
python link_checker.py ./
================================================
FILE: .github/workflows/stale.yml
================================================
name: "Stale bot of marking stale issues"
on:
schedule:
- cron: "50 18 * * *"
permissions:
issues: write
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has been open 30 days with no activity. This will be closed in 7 days.'
close-issue-message: "This issue has been automatically marked as stale because it hasn't had any recent activity.If you think this should still be open, or the problem still persists, just pop a reply in the comments and one of the maintainers will (try!) to follow up. Thank you for your interest and contribution to the Sping Cloud Alibaba Community."
days-before-issue-stale: 30
days-before-issue-close: 7
stale-issue-label: "stale"
close-issue-label: "wait-for-feedback"
exempt-all-milestones: true
operations-per-run: 10
days-before-pr-stale: -1
days-before-pr-close: -1
exempt-issue-labels: discussion,bug,question,good first issue
================================================
FILE: .gitignore
================================================
# Compiled class file
*.class
*.classpath
*.factorypath
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
!.mvn/wrapper/maven-wrapper.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# IDE Files #
*.iml
.idea
.idea/
.project
.settings
target
.DS_Store
.qoder
.cursor
.vscode
#Seata test data file
sessionStore/
# temp ignore
*.cache
*.diff
*.patch
*.tmp
# Maven ignore
.flattened-pom.xml
================================================
FILE: .licenscheckconfig.yaml
================================================
header:
license:
spdx-id: Apache-2.0
copyright-owner: alibaba
content: |
Copyright 2013-2023 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
paths-ignore:
- '.gitignore'
- '.gitattributes'
- '.travis.yml'
- 'codecov.yml'
- 'CONTRIBUTING.md'
- 'CONTRIBUTING_CN.md'
- 'CODE_OF_CONDUCT.md'
- 'README.md'
- 'LICENSE'
- 'NOTICE'
- '**/*.md'
- '.github/**'
- '**/*.yaml'
- "**/*.yml"
- '**/*.xml'
- '**/*.conf'
- '**/*.sql'
- '*.adoc'
- 'eclipse'
- '**/Dockerfile'
- '**/*.properties'
- '**/*.json'
- '**/*.html'
- "spring-cloud-alibaba-examples/integrated-example/docker-compose/.env"
#SPI、spring.factories、spring-configuration-metadata.json、additional-spring-configuration-metadata.json
- '**/src/test/resources/META-INF/**'
- '**/src/main/resources/META-INF/**'
- '**/target/**'
- '**/*.iml'
- 'mvnw'
- 'mvnw.cmd'
- '**/*.sh'
- '.mvn/**'
- 'sessionStore/**'
- 'distribution/LICENSE-BIN'
- 'distribution/NOTICE-BIN'
- 'test/src/test/resources/**'
- '**/src/test/resources/statelang/**'
comment: on-failure
dependency:
files:
- pom.xml
================================================
FILE: .mvn/jvm.config
================================================
-Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom
================================================
FILE: .mvn/wrapper/maven-wrapper.properties
================================================
# Copyright 2013-2023 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
================================================
FILE: CODE_OF_CONDUCT.md
================================================
## Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery
- Personal attacks
- Trolling or insulting/derogatory comments
- Public or private harassment
- Publishing other’s private information, such as physical or electronic addresses, without explicit permission
- Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org/), version 1.3.0, available at [contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/)
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README-zh.md
================================================
# Spring Cloud Alibaba
[](https://circleci.com/gh/alibaba/spring-cloud-alibaba/tree/2025.1.x)
[](https://search.maven.org/search?q=g:com.alibaba.cloud%20AND%20a:spring-cloud-alibaba-dependencies)
[](https://www.apache.org/licenses/LICENSE-2.0.html)
[](https://github.com/alibaba/spring-cloud-alibaba/actions)
[](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=sca)
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
此外,阿里云同时还提供了 Spring Cloud Alibaba 企业版 [微服务解决方案](https://www.aliyun.com/product/aliware/mse?spm=github.spring.com.topbar),包括无侵入服务治理(全链路灰度,无损上下线,离群实例摘除等),企业级 Nacos 注册配置中心和企业级云原生网关等众多产品。
参考文档 请查看 [WIKI](https://github.com/alibaba/spring-cloud-alibaba/wiki) 。
为 Spring Cloud Alibaba 贡献代码请参考 [如何贡献](https://sca.aliyun.com/docs/developer/contributor-guide/new-contributor-guide_dev/) 。
## 主要功能
* **服务限流降级**:默认支持 WebServlet、WebFlux、OpenFeign、RestTemplate、Spring Cloud Gateway、Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
* **服务注册与发现**:适配 Spring Cloud 服务注册与发现标准,默认集成对应 Spring Cloud 版本所支持的负载均衡组件的适配。
* **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。
* **消息驱动能力**:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
* **分布式事务**:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。
* **阿里云对象存储**:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
* **分布式任务调度**:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。
* **阿里云短信服务**:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
更多功能请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/Roadmap-zh.md)
除了上述所具有的功能外,针对企业级用户的场景,Spring Cloud Alibaba 配套的企业版微服务治理方案 [微服务引擎MSE](https://www.aliyun.com/product/aliware/mse?spm=github.spring.com.topbar) 还提供了企业级微服务治理中心,包括全链路灰度、服务预热、无损上下线和离群实例摘除等更多更强大的治理能力,同时还提供了企业级 Nacos 注册配置中心,企业级云原生网关等多种产品及解决方案。
## 组件
**[Sentinel](https://github.com/alibaba/Sentinel)**:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
**[Nacos](https://github.com/alibaba/Nacos)**:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
**[RocketMQ](https://rocketmq.apache.org/)**:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
**[Seata](https://github.com/seata/seata)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
**[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
**[Alibaba Cloud SchedulerX](https://cn.aliyun.com/aliware/schedulerx)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
更多组件请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/Roadmap-zh.md)。
## 如何构建
* 2025.1.x 分支对应的是 Spring Cloud 2025.1.x 与 Spring Boot 4.0.x,最低支持 JDK 17。
* 2025.0.x 分支对应的是 Spring Cloud 2025.0.x 与 Spring Boot 3.5.x,最低支持 JDK 17。
* 2023.x 分支对应的是 Spring Cloud 2023 与 Spring Boot 3.2.x,最低支持 JDK 17。
* 2022.x 分支对应的是 Spring Cloud 2022 与 Spring Boot 3.0.x,最低支持 JDK 17。
* 2021.x 分支对应的是 Spring Cloud 2021 与 Spring Boot 2.6.x,最低支持 JDK 1.8。
* 2020.0 分支对应的是 Spring Cloud 2020 与 Spring Boot 2.4.x,最低支持 JDK 1.8。
* 2.2.x 分支对应的是 Spring Cloud Hoxton 与 Spring Boot 2.2.x,最低支持 JDK 1.8。
* greenwich 分支对应的是 Spring Cloud Greenwich 与 Spring Boot 2.1.x,最低支持 JDK 1.8。
* finchley 分支对应的是 Spring Cloud Finchley 与 Spring Boot 2.0.x,最低支持 JDK 1.8。
* 1.x 分支对应的是 Spring Cloud Edgware 与 Spring Boot 1.x,最低支持 JDK 1.7。
Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone 到本地,然后执行以下命令:
```bash
./mvnw install
```
执行完毕后,项目将被安装到本地 Maven 仓库。
## 如何使用
### 如何引入依赖
#### 正式版
如果需要使用已发布的`正式版本`,在 `dependencyManagement` 中添加如下配置。
```xml
com.alibaba.cloudspring-cloud-alibaba-dependencies2025.1.0.0pomimport
```
然后在 `dependencies` 中添加自己所需使用的依赖即可使用。如果你想选择老版本,可以参考[版本说明](https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E)。
#### 快照
如果需要使用已发布的`快照版本`,在 `dependencyManagement` 中添加如下配置。
```xml
com.alibaba.cloudspring-cloud-alibaba-dependencies2025.1.0.0-SNAPSHOTpomimport
```
在 `repositories` 中添加如下配置。
```xml
githubhttps://maven.pkg.github.com/alibaba/spring-cloud-alibabafalsetrue
```
在 `settings.xml` 中添加如下配置。
```xml
github你的 GitHub 用户名你的 GitHub Token(需要 read:packages 权限)
```
## 演示 Demo
为了演示如何使用,Spring Cloud Alibaba 项目包含了一个子模块`spring-cloud-alibaba-examples`。此模块中提供了演示用的 example ,您可以阅读对应的 example 工程下的 readme 文档,根据里面的步骤来体验。
Example 列表:
[Sentinel Example](https://github.com/alibaba/spring-cloud-alibaba/tree/2025.1.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md)
[Nacos Example](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/spring-cloud-alibaba-examples/nacos-example/readme-zh.md)
[RocketMQ Example](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/spring-cloud-alibaba-examples/rocketmq-example/readme-zh.md)
[Seata Example](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/spring-cloud-alibaba-examples/seata-example/readme-zh.md)
[Alibaba Cloud OSS Example](https://github.com/alibaba/aliyun-spring-boot/tree/master/aliyun-spring-boot-samples/aliyun-oss-spring-boot-sample)
[Alibaba Cloud SMS Example](https://github.com/alibaba/aliyun-spring-boot/tree/master/aliyun-spring-boot-samples/aliyun-sms-spring-boot-sample)
[Alibaba Cloud SchedulerX Example](https://github.com/alibaba/aliyun-spring-boot)
## 版本管理规范
项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从 0 开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用 0,即版本号为 0.x.x 的格式。
由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,且 spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此我们采取跟 SpringBoot 版本号一致的版本:
* 1.5.x 版本适用于 Spring Boot 1.5.x
* 2.0.x 版本适用于 Spring Boot 2.0.x
* 2.1.x 版本适用于 Spring Boot 2.1.x
* 2.2.x 版本适用于 Spring Boot 2.2.x
* 2020.x 版本适用于 Spring Boot 2.4.x
* 2021.x 版本适用于 Spring Boot 2.6.x
* 2022.x 版本适用于 Spring Boot 3.0.x
* 2023.x 版本适用于 Spring Boot 3.2.x
* 2025.0.x 版本适用于 Spring Boot 3.5.x
* 2025.1.x 版本适用于 Spring Boot 4.0.x
## 社区交流
### 邮件列表
spring-cloud-alibaba@googlegroups.com,欢迎通过此邮件列表讨论与 spring-cloud-alibaba 相关的一切。
### 钉钉群
* Spring Cloud Alibaba 开源交流群(1群):21914947
* Spring Cloud Alibaba 开源交流群(2群,已满):21992595
* Spring Cloud Alibaba 开源交流群(3群,已满):35153903
* Spring Cloud Alibaba 开源交流群(4群,已满):30301472
* Spring Cloud Alibaba 开源交流群(5群,已满):34930571
* Spring Cloud Alibaba 开源交流群(6群,已满):34351718
* Spring Cloud Alibaba 开源交流群(7群):2415000986
## 社区相关开源
**[Nepxion Discovery](https://github.com/Nepxion/Discovery)**:一款集成Spring Cloud Alibaba、Nacos、Sentinel等阿里巴巴中间件,实现网关和服务的灰度发布、路由、权重、限流、熔断、降级、隔离、监控、追踪等功能的微服务开源解决。使用指南 请参考 **[Nepxion Discovery Guide](https://github.com/Nepxion/DiscoveryGuide)**。
================================================
FILE: README.md
================================================
# Spring Cloud Alibaba
[](https://circleci.com/gh/alibaba/spring-cloud-alibaba/tree/2025.1.x)
[](https://search.maven.org/search?q=g:com.alibaba.cloud%20AND%20a:spring-cloud-alibaba-dependencies)
[](https://www.apache.org/licenses/LICENSE-2.0.html)
[](https://github.com/alibaba/spring-cloud-alibaba/actions)
[](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=sca)
A project maintained by Alibaba.
See the [中文文档](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/README-zh.md) for Chinese readme.
Spring Cloud Alibaba provides a one-stop solution for distributed application development. It contains all the components required to develop distributed applications, making it easy for you to develop your applications using Spring Cloud.
With Spring Cloud Alibaba, you only need to add some annotations and a small amount of configurations to connect Spring Cloud applications to the distributed solutions of Alibaba, and build a distributed application system with Alibaba middleware.
## Features
* **Flow control and service degradation**: Flow control for HTTP services is supported by default. You can also customize flow control and service degradation rules using annotations. The rules can be changed dynamically.
* **Service registration and discovery**: Service can be registered and clients can discover the instances using Spring-managed beans. Load balancing is consistent with that supported by the corresponding Spring Cloud.
* **Distributed configuration**: Support for externalized configuration in a distributed system, auto refresh when configuration changes.
* **Event-driven**: Support for building highly scalable event-driven microservices connected with shared messaging systems.
* **Distributed Transaction**: Support for distributed transaction solution with high performance and ease of use.
* **Alibaba Cloud Object Storage**: Massive, secure, low-cost, and highly reliable cloud storage services. Support for storing and accessing any type of data in any application, anytime, anywhere.
* **Alibaba Cloud SchedulerX**: Accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds.
* **Alibaba Cloud SMS**: A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers.
For more features, please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/Roadmap.md).
In addition to the above-mentioned features, for the needs of enterprise users' scenarios, [Microservices Engine (MSE)](https://www.aliyun.com/product/aliware/mse?spm=github.spring.com.topbar) of Spring Cloud Alibaba's enterprise version provides an enterprise-level microservices governance center, which includes more powerful governance capabilities such as Grayscale Release, Service Warm-up, Lossless Online and Offline and Outlier Ejection. At the same time, it also provides a variety of products and solutions such as enterprise-level Nacos registration / configuration center, enterprise-level cloud native gateway.
## Components
**[Sentinel](https://github.com/alibaba/Sentinel)**: Sentinel takes "traffic flow" as the breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability.
**[Nacos](https://github.com/alibaba/Nacos)**: An easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.
**[RocketMQ](https://rocketmq.apache.org/)**: A distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.
**[Seata](https://github.com/seata/seata)**: A distributed transaction solution with high performance and ease of use for microservices architecture.
**[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: An encrypted and secure cloud storage service which stores, processes and accesses massive amounts of data from anywhere in the world.
**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers.
**[Alibaba Cloud SchedulerX](https://www.aliyun.com/aliware/schedulerx?spm=5176.10695662.784137.1.4b07363dej23L3)**: Accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds.
For more features please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/Roadmap.md).
## How to build
* **2025.1.x branch**: Corresponds to Spring Cloud 2025.1.x & Spring Boot 4.0.x, JDK 17 or later versions are supported.
* **2025.0.x branch**: Corresponds to Spring Cloud 2025.0.x & Spring Boot 3.5.x, JDK 17 or later versions are supported.
* **2023.x branch**: Corresponds to Spring Cloud 2023 & Spring Boot 3.2.x, JDK 17 or later versions are supported.
* **2022.x branch**: Corresponds to Spring Cloud 2022 & Spring Boot 3.0.x, JDK 17 or later versions are supported.
* **2021.x branch**: Corresponds to Spring Cloud 2021 & Spring Boot 2.6.x. JDK 1.8 or later versions are supported.
* **2020.0 branch**: Corresponds to Spring Cloud 2020 & Spring Boot 2.4.x. JDK 1.8 or later versions are supported.
* **2.2.x branch**: Corresponds to Spring Cloud Hoxton & Spring Boot 2.2.x. JDK 1.8 or later versions are supported.
* **greenwich branch**: Corresponds to Spring Cloud Greenwich & Spring Boot 2.1.x. JDK 1.8 or later versions are supported.
* **finchley branch**: Corresponds to Spring Cloud Finchley & Spring Boot 2.0.x. JDK 1.8 or later versions are supported.
* **1.x branch**: Corresponds to Spring Cloud Edgware & Spring Boot 1.x, JDK 1.7 or later versions are supported.
Spring Cloud uses Maven for most build-related activities, and you should be able to get off the ground quite quickly by cloning the project you are interested in and typing:
```bash
./mvnw install
```
## How to Use
### Add maven dependency
#### Release Version
These artifacts are available from Maven Central and Spring Release repository via BOM:
```xml
com.alibaba.cloudspring-cloud-alibaba-dependencies2025.1.0.0pomimport
```
add the module in `dependencies`. If you want to choose an older version, you can refer to the [Release Notes](https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E).
#### Snapshot
If you need to use the already published `Snapshot Version`, add the following configuration in the `dependencyManagement`.
```xml
com.alibaba.cloudspring-cloud-alibaba-dependencies2025.1.0.0-SNAPSHOTpomimport
```
Add the following configuration in `repositories`.
```xml
githubhttps://maven.pkg.github.com/alibaba/spring-cloud-alibabafalsetrue
```
Add the following configuration in `settings.xml`.
```xml
githubYour GitHub UsernameYour GitHub Token (requires read:packages permission)
```
## Examples
A `spring-cloud-alibaba-examples` module is included in our project for you to get started with Spring Cloud Alibaba quickly. It contains an example, and you can refer to the readme file in the example project for a quick walkthrough.
Examples:
[Sentinel Example](https://github.com/alibaba/spring-cloud-alibaba/tree/2025.1.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md)
[Nacos Example](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/spring-cloud-alibaba-examples/nacos-example/readme.md)
[RocketMQ Example](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/spring-cloud-alibaba-examples/rocketmq-example/readme.md)
[Alibaba Cloud OSS Example](https://github.com/alibaba/aliyun-spring-boot/tree/master/aliyun-spring-boot-samples/aliyun-oss-spring-boot-sample)
## Version control guidelines
The version number of the project is in the form of x.x.x, where x is a number, starting from 0, and is not limited to the range 0~9. When the project is in the incubator phase, the version number is 0.x.x.
As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been changed significantly in the Actuator module, and spring-cloud-commons is also changed quite a lot from 1.x.x to 2.0.0, we take the same version rule as SpringBoot version number.
* 1.5.x for Spring Boot 1.5.x
* 2.0.x for Spring Boot 2.0.x
* 2.1.x for Spring Boot 2.1.x
* 2.2.x for Spring Boot 2.2.x
* 2020.x for Spring Boot 2.4.x
* 2021.x for Spring Boot 2.6.x
* 2022.x for Spring Boot 3.0.x
* 2023.x for Spring Boot 3.2.x
* 2025.0.x for Spring Boot 3.5.x
* 2025.1.x for Spring Boot 4.0.x
## Code of Conduct
This project is a sub-project of Spring Cloud, it adheres to the Contributor Covenant [code of conduct](https://sca.aliyun.com/en-us/community/developer/contributor-guide/new-contributor-guide_dev/). By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
## Code Conventions and Housekeeping
None of these is essential for a pull request, but they will all help. They can also be added after the original pull request but before a merge.
Use the Spring Framework code format conventions. If you use Eclipse you can import formatter settings using the eclipse-code-formatter.xml file from the Spring Cloud Build project. If using IntelliJ, you can use the Eclipse Code Formatter Plugin to import the same file.
Make sure all new .java files to have a simple Javadoc class comment with at least an @author tag identifying you, and preferably at least a paragraph on what the class is for.
Add the ASF license header comment to all new .java files (copy from existing files in the project)
Add yourself as an @author to the .java files that you modify substantially (more than cosmetic changes).
Add some Javadocs and, if you change the namespace, some XSD doc elements.
A few unit tests would help a lot as well —— someone has to do it.
If no-one else is using your branch, please rebase it against the current 2023.x (or other target branch in the main project).
When writing a commit message please follow these conventions, if you are fixing an existing issue please add Fixes gh-XXXX at the end of the commit message (where XXXX is the issue number).
## Contact Us
Mailing list is recommended for discussing almost anything related to spring-cloud-alibaba.
spring-cloud-alibaba@googlegroups.com: You can ask questions here if you encounter any problem when using or developing spring-cloud-alibaba.
================================================
FILE: Roadmap-zh.md
================================================
# Roadmap
[Spring Cloud Alibaba](https://github.com/alibaba/spring-cloud-alibaba) 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
此项目包含的组件内容,主要选取自阿里巴巴开源中间件,但也不限定于这些产品。
如果您对 Roadmap 有任何建议或想法,欢迎在 issues 中或者通过其他社区渠道向我们提出,一起讨论。
- Github Issue:https://github.com/alibaba/spring-cloud-alibaba/issues
- 钉钉交流群:“群8 Spring Cloud Alibaba交流群”群的钉钉群号: 33610001098
## 已包含的组件
**Sentinel**
阿里巴巴开源产品,把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
**Nacos**
阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
**RocketMQ**
Apache RocketMQ™ 一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
**Seata**
阿里巴巴开源产品(现捐赠给 Apache 基金会),一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
## 未来发展方向
## Spring Cloud Admin 服务治理(可观测方向)
Spring Cloud Admin 定位为一款可视化的微服务管控平台,通过它能够查看整个 Spring Cloud 微服务状态(包括服务数、实例数、应用数等)。同时 Spring Cloud Admin 还应与主流的 [Apache SkyWalking](https://skywalking.apache.org/),[OpenTelemetry](https://opentelemetry.io/) 等可观测性系统集成,提供对集群状态的指标查询与监控能力。
## Spring Cloud Alibaba AI
随着 LLM 的爆火,各种 AI 应用开发框架应运而生。其中包括 LangChain,LangChain4J,Spring AI 等项目,为 AI 应用开发提供了一系列的解决方案。
本项目是基于 Spring AI 提供对阿里通义系列大模型的完整支持,包括对话,文生图,文生语音,语音转录等功能。旨在为开发微服务 AI 应用提供便利,屏蔽底层复杂性,使得 AI 可以快速接入 Spring Cloud 微服务体系。
## Proxyless Mesh
Spring Cloud Alibaba 也积极在 Proxyless 方向上探索,目前已经完成了 Routing,Xds-adapter 等功能。未来会推出更多云原生场景下的 Proxyless 功能特性。
## RPC 方向上的探索
Spring Cloud Alibaba RPC 组件主要依赖于 OpenFeign,RestTemplate 等。社区计划通过加入 GRPC,Dubbo 的 rpc 解决方案,进一步增强社区的 RPC 组件能力。
## 分布式任务调度
Spring Cloud Alibaba 缺少对分布式调度任务的支持,社区计划通过适配开源的分布式任务调度框架,来完善这部分能力。
================================================
FILE: Roadmap.md
================================================
# Roadmap
See the [中文文档](https://github.com/alibaba/spring-cloud-alibaba/blob/2025.1.x/Roadmap-zh.md) for Chinese Roadmap.
Spring Cloud Alibaba provides a one-stop solution for microservices development. It contains all the components required to develop distributed applications, making it easy for you to develop your applications through the Spring Cloud programming model.
This project contains components from both open-source and commercialized Alibaba middleware products,but are not limited to them.
If you have any suggestions on our roadmap, feel free to submit issues or contact us via the other channels.
- Github Issue:https://github.com/alibaba/spring-cloud-alibaba/issues
- DingTalk communication group: "Group 8 Spring Cloud Alibaba communication group" DingTalk group number: 33610001098
## Components
**Sentinel**
An open-source project of Alibaba, Sentinel takes "flow" as breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability.
**Nacos**
An opensource project of Alibaba, an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.
**RocketMQ**
Apache RocketMQ™ is an open source distributed messaging system based on highly available distributed cluster technology, providing low latency, highly reliable message publishing and subscription services.
**Seata**
An opensource project of Alibaba(now donated to the Apache Foundation), a distributed transaction solution dedicated to providing high-performance and easy-to-use distributed transaction services under a microservice architecture.
## Future Development Direction
## Spring Cloud Admin Service Governance (Observable Direction)
Spring Cloud Admin is positioned as a visual microservice management and control platform, through which you can view the status of the entire Spring Cloud microservice (including the number of services, the number of instances, the number of applications, etc.). At the same time, Spring Cloud Admin should also be integrated with mainstream observability systems such as [Apache SkyWalking](https://skywalking.apache.org/) and [OpenTelemetry](https://opentelemetry.io/) to provide indicator query and monitoring capabilities for cluster status.
## Spring Cloud Alibaba AI
With the explosion of LLM, various AI application development frameworks have emerged as the times require. These include LangChain, LangChain4J, Spring AI and other projects, providing a series of solutions for AI application development.
This project is based on Spring AI to provide complete support for Ali Tongyi series large models, providing for chat, text-to-image, audiotranscription and other functions. It aims to facilitate the development of microservice AI applications, shield the underlying complexity, and enable AI to quickly access the Spring Cloud microservice system.
## Proxyless Mesh
Spring Cloud Alibaba is also actively exploring in the direction of Proxyless, and has completed functions such as Routing and Xds-adapter. In the future, more Proxyless features in cloud-native scenarios will be launched.
## Exploration in the direction of RPC
Spring Cloud Alibaba RPC components mainly rely on OpenFeign, RestTemplate, etc. The community plans to further enhance the community's RPC component capabilities by joining GRPC, Dubbo's RPC solution.
## Distributed task scheduling
Spring Cloud Alibaba lacks support for distributed scheduling tasks, the community plans to improve this part of the ability by adapting open source distributed task scheduling framework.
================================================
FILE: eclipse/checkstyle-suppressions.xml
================================================
================================================
FILE: eclipse/eclipse-code-formatter.xml
================================================
================================================
FILE: eclipse/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
org.eclipse.jdt.core.codeComplete.fieldPrefixes=
org.eclipse.jdt.core.codeComplete.fieldSuffixes=
org.eclipse.jdt.core.codeComplete.localPrefixes=
org.eclipse.jdt.core.codeComplete.localSuffixes=
org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
org.eclipse.jdt.core.compiler.problem.deadCode=warning
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=default
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags
org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=default
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nullReference=ignore
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.processAnnotations=disabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=false
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=90
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=90
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=tab
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_on_off_tags=true
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
================================================
FILE: eclipse/org.eclipse.jdt.ui.prefs
================================================
cleanup.add_default_serial_version_id=true
cleanup.add_generated_serial_version_id=false
cleanup.add_missing_annotations=true
cleanup.add_missing_deprecated_annotations=true
cleanup.add_missing_methods=false
cleanup.add_missing_nls_tags=false
cleanup.add_missing_override_annotations=true
cleanup.add_missing_override_annotations_interface_methods=true
cleanup.add_serial_version_id=false
cleanup.always_use_blocks=true
cleanup.always_use_parentheses_in_expressions=false
cleanup.always_use_this_for_non_static_field_access=true
cleanup.always_use_this_for_non_static_method_access=false
cleanup.convert_functional_interfaces=false
cleanup.convert_to_enhanced_for_loop=false
cleanup.correct_indentation=false
cleanup.format_source_code=true
cleanup.format_source_code_changes_only=false
cleanup.insert_inferred_type_arguments=false
cleanup.make_local_variable_final=false
cleanup.make_parameters_final=false
cleanup.make_private_fields_final=false
cleanup.make_type_abstract_if_missing_method=false
cleanup.make_variable_declarations_final=false
cleanup.never_use_blocks=false
cleanup.never_use_parentheses_in_expressions=true
cleanup.organize_imports=true
cleanup.qualify_static_field_accesses_with_declaring_class=false
cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
cleanup.qualify_static_member_accesses_with_declaring_class=true
cleanup.qualify_static_method_accesses_with_declaring_class=false
cleanup.remove_private_constructors=true
cleanup.remove_redundant_type_arguments=true
cleanup.remove_trailing_whitespaces=true
cleanup.remove_trailing_whitespaces_all=true
cleanup.remove_trailing_whitespaces_ignore_empty=false
cleanup.remove_unnecessary_casts=true
cleanup.remove_unnecessary_nls_tags=false
cleanup.remove_unused_imports=true
cleanup.remove_unused_local_variables=false
cleanup.remove_unused_private_fields=true
cleanup.remove_unused_private_members=false
cleanup.remove_unused_private_methods=true
cleanup.remove_unused_private_types=true
cleanup.sort_members=false
cleanup.sort_members_all=false
cleanup.use_anonymous_class_creation=false
cleanup.use_blocks=true
cleanup.use_blocks_only_for_return_and_throw=false
cleanup.use_lambda=true
cleanup.use_parentheses_in_expressions=false
cleanup.use_this_for_non_static_field_access=false
cleanup.use_this_for_non_static_field_access_only_if_necessary=false
cleanup.use_this_for_non_static_method_access=false
cleanup.use_this_for_non_static_method_access_only_if_necessary=true
cleanup.use_type_arguments=false
cleanup_profile=_Spring Cloud Cleanup Conventions
cleanup_settings_version=2
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Spring Cloud Java Conventions
formatter_settings_version=13
org.eclipse.jdt.ui.exception.name=e
org.eclipse.jdt.ui.gettersetter.use.is=true
org.eclipse.jdt.ui.ignorelowercasenames=true
org.eclipse.jdt.ui.importorder=java;javax;;org.springframework;\#;
org.eclipse.jdt.ui.javadoc=true
org.eclipse.jdt.ui.keywordthis=false
org.eclipse.jdt.ui.ondemandthreshold=9999
org.eclipse.jdt.ui.overrideannotation=true
org.eclipse.jdt.ui.staticondemandthreshold=9999
org.eclipse.jdt.ui.text.custom_code_templates=/**\n * @return the ${bare_field_name}\n *//**\n * @param ${param} the ${bare_field_name} to set\n *//**\n * ${tags}\n *//*\n * Copyright 2013-2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http\://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *//**\n * @author ${user}\n *//**\n * \n *//**\n * ${tags}\n *//* (non-Javadoc)\n * ${see_to_overridden}\n *//**\n * ${tags}\n * ${see_to_target}\n */${filecomment}\n\n${package_declaration}\n${typecomment}\n${type_declaration}\n\n\n\n// ${todo} Auto-generated catch block\nthrow new UnsupportedOperationException("Auto-generated method stub", ${exception_var});// ${todo} Auto-generated method stub\nthrow new UnsupportedOperationException("Auto-generated method stub");${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
sp_cleanup.add_missing_override_annotations=true
sp_cleanup.add_missing_override_annotations_interface_methods=true
sp_cleanup.add_serial_version_id=false
sp_cleanup.always_use_blocks=true
sp_cleanup.always_use_parentheses_in_expressions=true
sp_cleanup.always_use_this_for_non_static_field_access=true
sp_cleanup.always_use_this_for_non_static_method_access=false
sp_cleanup.convert_to_enhanced_for_loop=false
sp_cleanup.correct_indentation=false
sp_cleanup.format_source_code=true
sp_cleanup.format_source_code_changes_only=false
sp_cleanup.make_local_variable_final=false
sp_cleanup.make_parameters_final=false
sp_cleanup.make_private_fields_final=false
sp_cleanup.make_type_abstract_if_missing_method=false
sp_cleanup.make_variable_declarations_final=false
sp_cleanup.never_use_blocks=false
sp_cleanup.never_use_parentheses_in_expressions=false
sp_cleanup.on_save_use_additional_actions=true
sp_cleanup.organize_imports=true
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_trailing_whitespaces=true
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
sp_cleanup.remove_unnecessary_casts=true
sp_cleanup.remove_unnecessary_nls_tags=false
sp_cleanup.remove_unused_imports=true
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
sp_cleanup.remove_unused_private_members=false
sp_cleanup.remove_unused_private_methods=true
sp_cleanup.remove_unused_private_types=true
sp_cleanup.sort_members=false
sp_cleanup.sort_members_all=false
sp_cleanup.use_blocks=true
sp_cleanup.use_blocks_only_for_return_and_throw=false
sp_cleanup.use_parentheses_in_expressions=false
sp_cleanup.use_this_for_non_static_field_access=true
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
sp_cleanup.use_this_for_non_static_method_access=false
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
================================================
FILE: mvnw
================================================
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
================================================
FILE: mvnw.cmd
================================================
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%
================================================
FILE: pom.xml
================================================
4.0.0org.springframework.cloudspring-cloud-build5.0.0com.alibaba.cloudspring-cloud-alibaba${revision}pomSpring Cloud AlibabaSpring Cloud Alibabahttps://github.com/alibaba/spring-cloud-alibabaApache License, Version 2.0https://www.apache.org/licenses/LICENSE-2.0.txtrepohttps://github.com/alibaba/spring-cloud-alibaba
scm:git:git://github.com/alibaba/spring-cloud-alibaba.git
scm:git:ssh://git@github.com/alibaba/spring-cloud-alibaba.git
HEADxiaojingflystar32@163.comJim Fangfangjian0423@gmail.comAlibabahttps://github.com/fangjian0423xiaolongzuo150349407@qq.comhengyunabchengyunabc@gmail.commercyblitzMercy Mamercyblitz@gmail.comAlibabahttps://github.com/mercyblitzyunzhengyunzheng1228@gmail.comtheonefxtheonefxchenxilzx1@gmail.comAlibabahttps://github.com/theonefx2025.1.0.1-SNAPSHOT2025.1.04.0.017173.14.03.1.43.5.33.2.13.11.23.2.71.7.04.4.10.8.130.10.60.7.0spring-cloud-alibaba-dependenciesspring-cloud-alibaba-examplesspring-cloud-alibaba-startersspring-cloud-alibaba-coveragespring-cloud-alibaba-testsorg.springframework.bootspring-boot-dependencies${spring-boot.version}pomimportorg.springframework.cloudspring-cloud-dependencies${spring.cloud.version}pomimportcom.alibaba.cloudspring-cloud-alibaba-dependencies${project.version}pomimportorg.jacocojacoco-maven-plugin${jacoco.version}io.spring.javaformatspring-javaformat-maven-plugin${spring-javaformat.version}validatetrueorg.sonatype.centralcentral-publishing-maven-plugin${central.publishing.maven.version}org.apache.maven.pluginsmaven-eclipse-pluginfalse.settings/org.eclipse.jdt.ui.prefs
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.ui.prefs
.settings/org.eclipse.jdt.core.prefs
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.core.prefs
org.apache.maven.pluginsmaven-checkstyle-plugincheckstyle-validationvalidatecheck${maven.multiModuleProjectDirectory}/eclipse/checkstyle-suppressions.xmltruetruetruetruewarningorg.apache.maven.pluginsmaven-compiler-plugin${maven-compiler-plugin.version}true${maven.compiler.source}${maven.compiler.target}org.apache.maven.pluginsmaven-surefire-plugin${maven-surefire-plugin.version}true1falseorg.codehaus.mojoflatten-maven-plugin${flatten-maven-plugin.version}trueresolveCiFriendliesOnlyflattenprocess-resourcesflattenflatten.cleancleancleanorg.apache.maven.pluginsmaven-checkstyle-plugingithubhttps://maven.pkg.github.com/alibaba/spring-cloud-alibabareleaseorg.apache.maven.pluginsmaven-source-plugin${maven-source-plugin.version}packagejar-no-forkorg.apache.maven.pluginsmaven-javadoc-plugin${maven-javadoc-plugin.version}none${maven.compiler.source}packagejarorg.apache.maven.pluginsmaven-gpg-plugin${maven-gpg-plugin.version}verifysignorg.sonatype.centralcentral-publishing-maven-plugintruecentralspring-cloud-alibaba-coveragesentinel-core-examplesentinel-openfeign-examplesentinel-resttemplate-examplesentinel-circuitbreaker-examplesentinel-webflux-examplesentinel-spring-cloud-gateway-examplenacos-discovery-examplenacos-config-examplenacos-gateway-examplebusiness-serviceorder-servicestorage-serviceaccount-servicespring-cloud-alibaba-examplesrocketmq-comprehensive-examplerocketmq-orderly-consume-examplerocketmq-broadcast-producer-examplerocketmq-broadcast-consumer1-examplerocketmq-broadcast-consumer2-examplerocketmq-delay-consume-examplerocketmq-sql-consume-examplerocketmq-example-commonrocketmq-tx-examplerocketmq-pollable-consume-examplespring-cloud-bus-rocketmq-examplespring-cloud-alibaba-sidecar-nacos-examplespring-cloud-alibaba-sidecar-consul-examplenacos-gateway-discovery-examplenacos-discovery-provider-examplenacos-discovery-consumer-sclb-examplenacos-discovery-spring-cloud-config-client-examplenacos-discovery-consumer-examplenacos-reactivediscovery-consumer-examplenacos-gateway-provider-examplenacos-discovery-spring-cloud-config-server-exampleintegrated-storageintegrated-accountintegrated-orderintegrated-gatewayintegrated-praise-providerintegrated-praise-consumerintegrated-commonintegrated-frontendspring-cloud-scheduling-examplespring-cloud-alibaba-test-supportnacos-testsnacos-config-testnacos-discovery-testrocketmq-testsrocketmq-stream-testsentinel-testssentinel-flowcontrol-testsentinel-degrade-test
================================================
FILE: spring-cloud-alibaba-coverage/pom.xml
================================================
4.0.0com.alibaba.cloudspring-cloud-alibaba${revision}../pom.xmlspring-cloud-alibaba-coverageSpring Cloud Alibaba Coveragecom.alibaba.cloudspring-cloud-alibaba-sentinel-datasource${revision}com.alibaba.cloudspring-cloud-starter-alibaba-sentinel${revision}com.alibaba.cloudspring-cloud-circuitbreaker-sentinel${revision}com.alibaba.cloudspring-cloud-starter-alibaba-seata${revision}com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery${revision}com.alibaba.cloudspring-cloud-starter-alibaba-nacos-config${revision}com.alibaba.cloudspring-cloud-starter-stream-rocketmq${revision}com.alibaba.cloudspring-cloud-starter-bus-rocketmq${revision}com.alibaba.cloudspring-cloud-starter-alibaba-sidecar${revision}org.jacocojacoco-maven-plugin${jacoco.version}report-aggregatetestreport-aggregate${basedir}/../target/site/jacocoorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-dependencies/pom.xml
================================================
4.0.0org.springframework.cloudspring-cloud-dependencies-parent5.0.0com.alibaba.cloudspring-cloud-alibaba-dependencies${revision}pomSpring Cloud Alibaba DependenciesSpring Cloud Alibaba Dependencies2025.1.0.1-SNAPSHOT1.8.93.1.12.6.05.3.15.10.01.13.317173.2.13.11.23.2.71.7.00.7.01.2.273.0.52.25.12.0.172.0.582.25.133.4.8-jre1.18.38com.alibaba.nacosnacos-client${nacos.client.version}com.alibaba.cspsentinel-core${sentinel.version}com.alibaba.cspsentinel-parameter-flow-control${sentinel.version}com.alibaba.cspsentinel-datasource-extension${sentinel.version}com.alibaba.cspsentinel-datasource-apollo${sentinel.version}com.alibaba.cspsentinel-datasource-zookeeper${sentinel.version}com.alibaba.cspsentinel-datasource-nacos${sentinel.version}com.alibaba.cspsentinel-datasource-redis${sentinel.version}com.alibaba.cspsentinel-datasource-consul${sentinel.version}com.alibaba.cspsentinel-web-servlet${sentinel.version}com.alibaba.cspsentinel-spring-cloud-gateway-v6x-adapter${sentinel.version}com.alibaba.cspsentinel-transport-simple-http${sentinel.version}com.alibaba.cspsentinel-annotation-aspectj${sentinel.version}com.alibaba.cspsentinel-reactor-adapter${sentinel.version}com.alibaba.cspsentinel-cluster-server-default${sentinel.version}com.alibaba.cspsentinel-cluster-client-default${sentinel.version}com.alibaba.cspsentinel-spring-webflux-adapter${sentinel.version}com.alibaba.cspsentinel-api-gateway-adapter-common${sentinel.version}com.alibaba.cspsentinel-spring-webmvc-v6x-adapter${sentinel.version}org.apache.seataseata-spring-boot-starter${seata.version}org.apache.rocketmqrocketmq-client${rocketmq.version}org.apache.rocketmqrocketmq-acl${rocketmq.version}net.javacrumbs.shedlockshedlock-spring${shedlock.version}net.javacrumbs.shedlockshedlock-provider-jdbc-template${shedlock.version}com.aliyun.schedulerxschedulerx2-worker${schedulerx.worker.version}com.alibaba.cloudspring-cloud-alibaba-sentinel-datasource${revision}com.alibaba.cloudspring-cloud-alibaba-sentinel-gateway${revision}com.alibaba.cloudspring-cloud-starter-alibaba-sentinel${revision}com.alibaba.cloudspring-cloud-circuitbreaker-sentinel${revision}com.alibaba.cloudspring-cloud-starter-alibaba-seata${revision}com.alibaba.cloudspring-alibaba-nacos-config${revision}com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery${revision}com.alibaba.cloudspring-cloud-starter-alibaba-nacos-config${revision}com.alibaba.cloudspring-cloud-starter-stream-rocketmq${revision}com.alibaba.cloudspring-cloud-starter-bus-rocketmq${revision}com.alibaba.cloudspring-cloud-starter-alibaba-sidecar${revision}com.alibaba.cloudspring-cloud-alibaba-commons${revision}com.alibaba.cloudspring-cloud-starter-alibaba-schedulerx${revision}com.alibabadruid-spring-boot-starter${druid.version}com.alibabadruid${druid.version}org.mybatis.spring.bootmybatis-spring-boot-starter${mybatis.version}org.apache.logging.log4jlog4j-core${log4j-core.version}org.slf4jslf4j-api${slf4j-api.version}com.alibabafastjson${fastjson.version}org.apache.logging.log4jlog4j-slf4j2-impl${log4j-slf4j2-impl.version}com.google.guavaguava${guava.version}org.projectlomboklombok${lombok.version}githubhttps://maven.pkg.github.com/alibaba/spring-cloud-alibabareleaseorg.apache.maven.pluginsmaven-source-plugin${maven-source-plugin.version}packagejar-no-forkorg.apache.maven.pluginsmaven-javadoc-plugin${maven-javadoc-plugin.version}packagejarorg.apache.maven.pluginsmaven-gpg-plugin${maven-gpg-plugin.version}verifysignorg.codehaus.mojoflatten-maven-plugin${flatten-maven-plugin.version}trueresolveCiFriendliesOnlyflattenprocess-resourcesflattenflatten.cleancleancleanorg.sonatype.centralcentral-publishing-maven-plugin${central.publishing.maven.version}truecentral
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/config/datasource-config.yaml
================================================
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: 'root'
password: 'root'
main:
allow-bean-definition-overriding: true
mybatis:
configuration:
map-underscore-to-camel-case: true
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/config/integrated-account.yaml
================================================
spring:
datasource:
url: jdbc:mysql://integrated-mysql:3306/integrated_account?useSSL=false&characterEncoding=utf8
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/config/integrated-consumer.yaml
================================================
spring:
datasource:
url: jdbc:mysql://integrated-mysql:3306/integrated_praise?useSSL=false&characterEncoding=utf8
cloud:
stream:
function:
definition: consumer;
bindings:
consumer-in-0:
destination: PRAISE-TOPIC-01
content-type: application/json
group: praise-consumer-group-PRAISE-TOPIC-01
rocketmq:
binder:
name-server: rocketmq:9876
bindings:
consumer-in-0:
consumer:
pullInterval: 4000
pullBatchSize: 4
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/config/integrated-gateway.yaml
================================================
spring:
cloud:
gateway:
routes:
- id: placeOrder
uri: lb://integrated-order
predicates:
- Path=/order/create
- id: queryStorage
uri: lb://integrated-storage
predicates:
- Path=/storage/
- id: queryAccount
uri: lb://integrated-account
predicates:
- Path=/account/
- id: praiseItemRocketMQ
uri: lb://integrated-provider
predicates:
- Path=/praise/rocketmq
- id: praiseItemSentinel
uri: lb://integrated-provider
predicates:
- Path=/praise/sentinel
- id: queryPraise
uri: lb://integrated-consumer
predicates:
- Path=/praise/query
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/config/integrated-order.yaml
================================================
spring:
datasource:
url: jdbc:mysql://integrated-mysql:3306/integrated_order?useSSL=false&characterEncoding=utf8
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/config/integrated-provider.yaml
================================================
spring:
cloud:
stream:
bindings:
praise-output:
destination: PRAISE-TOPIC-01
content-type: application/json
rocketmq:
binder:
name-server: rocketmq:9876
bindings:
praise-output:
producer:
group: test
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/config/integrated-storage.yaml
================================================
spring:
datasource:
url: jdbc:mysql://integrated-mysql:3306/integrated_storage?useSSL=false&characterEncoding=utf8
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/rocketmq/broker.conf
================================================
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
brokerIP1=172.20.0.4
brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/scripts/nacos-config-quick.sh
================================================
#!/bin/sh
echo "Nacos auto config started"
datasourceConfig=$(cat ../config/datasource-config.yaml)
storageConfig=$(cat ../config/integrated-storage.yaml)
accountConfig=$(cat ../config/integrated-account.yaml)
orderConfig=$(cat ../config/integrated-order.yaml)
gatewayConfig=$(cat ../config/integrated-gateway.yaml)
providerConfig=$(cat ../config/integrated-provider.yaml)
consumerConfig=$(cat ../config/integrated-consumer.yaml)
groupId="integrated-example"
curl -X POST "nacos-server:8848/nacos/v1/cs/configs" -d "dataId=datasource-config.yaml&group=${groupId}&content=${datasourceConfig}"
curl -X POST "nacos-server:8848/nacos/v1/cs/configs" -d "dataId=integrated-storage.yaml&group=${groupId}&content=${storageConfig}"
curl -X POST "nacos-server:8848/nacos/v1/cs/configs" -d "dataId=integrated-account.yaml&group=${groupId}&content=${accountConfig}"
curl -X POST "nacos-server:8848/nacos/v1/cs/configs" -d "dataId=integrated-order.yaml&group=${groupId}&content=${orderConfig}"
curl -X POST "nacos-server:8848/nacos/v1/cs/configs" -d "dataId=integrated-gateway.yaml&group=${groupId}&content=${gatewayConfig}"
curl -X POST "nacos-server:8848/nacos/v1/cs/configs" -d "dataId=integrated-provider.yaml&group=${groupId}&content=${providerConfig}"
curl -X POST "nacos-server:8848/nacos/v1/cs/configs" -d "dataId=integrated-consumer.yaml&group=${groupId}&content=${consumerConfig}"
echo "Nacos config pushed successfully finished"
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/config-init/sql/init.sql
================================================
-- Storage库存微服务的数据库业务初始化
DROP DATABASE IF EXISTS integrated_storage;
CREATE DATABASE integrated_storage;
USE integrated_storage;
CREATE TABLE `storage`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARSET = utf8;
INSERT INTO `storage`
VALUES ('1', '1', '100', '2022-08-07 22:48:29', '2022-08-14 13:49:05');
-- Account账户微服务的数据库业务初始化
DROP DATABASE IF EXISTS integrated_account;
CREATE DATABASE integrated_account;
USE integrated_account;
CREATE TABLE `account`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARSET = utf8;
INSERT INTO `account`
VALUES ('1', 'admin', '3', '2022-08-07 22:53:01', '2022-08-14 13:49:05');
-- Order订单微服务的数据库业务初始化
DROP DATABASE IF EXISTS integrated_order;
CREATE DATABASE integrated_order;
USE integrated_order;
CREATE TABLE `order`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
`money` int(11) DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 16
DEFAULT CHARSET = utf8;
-- 点赞业务的数据库初始化
DROP DATABASE IF EXISTS integrated_praise;
CREATE DATABASE integrated_praise;
USE integrated_praise;
CREATE TABLE `item`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`praise` int(11) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARSET = utf8;
INSERT INTO `item`
VALUES ('1', '0', '2022-08-14 00:33:50', '2022-08-14 14:07:34');
-- Storage库存微服务的数据库Seata初始化
USE integrated_storage;
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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- Storage库存微服务的数据库Seata初始化
USE integrated_account;
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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- Storage库存微服务的数据库Seata初始化
USE integrated_order;
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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docker-compose/docker-compose-env.yml
================================================
version: "3"
services:
# nacos
nacos:
image: nacos/nacos-server:v3.1.0
hostname: nacos-server
restart: always
container_name: integrated-example-nacos
environment:
- PREFER_HOST_MODE=hostname
- MODE=standalone
ports:
- "8848:8848"
# mysql
mysql:
container_name: integrated-example-mysql
hostname: integrated-mysql
restart: always
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: integrated_storage
ports:
- "3306:3306"
volumes:
- ../config-init/sql/init.sql:/docker-entrypoint-initdb.d/init.sql
command:
[
--character-set-server=utf8mb4,
--collation-server=utf8mb4_unicode_ci
]
# rocketMQ
rmqnamesrv:
image: apache/rocketmq:4.9.4
hostname: rocketmq
restart: always
container_name: integrated-example-rmqnamesrv
ports:
- "9876:9876"
command: sh mqnamesrv
rmqbroker:
image: apache/rocketmq:4.9.4
restart: always
container_name: integrated-example-rmqbroker
ports:
- "10909:10909"
- "10911:10911"
volumes:
- ../config-init/rocketmq/broker.conf:/opt/rocketmq-4.9.4/conf/broker.conf
environment:
NAMESRV_ADDR: "rmqnamesrv:9876"
JAVA_OPTS: " -Duser.home=/opt"
JAVA_OPT_EXT: "-server -Xms128m -Xmx128m -Xmn128m"
command: sh mqbroker -c /opt/rocketmq-4.9.4/conf/broker.conf
depends_on:
- rmqnamesrv
# seata
seata-server:
image: seataio/seata-server:1.5.1
hostname: seata-server
restart: always
container_name: integrated-example-seata-server
ports:
- "8091:8091"
environment:
- SEATA_PORT=8091
- STORE_MODE=file
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docker-compose/docker-compose-service.yml
================================================
version: "3"
services:
# integrated example module
integrated-frontend:
image: integrated-frontend
hostname: integrated-frontend
build:
dockerfile: ./integrated-frontend/Dockerfile
context: ../
env_file:
- .env
container_name: integrated-frontend
ports:
- ${FRONTEND_PORT}:${FRONTEND_PORT}
depends_on:
- integrated-gateway
- integrated-account
- integrated-order
- integrated-storage
- integrated-praise-consumer
- integrated-praise-provider
integrated-gateway:
image: integrated-gateway
hostname: gateway-service
build:
dockerfile: ./integrated-gateway/Dockerfile
context: ../
env_file:
- .env
container_name: integrated-gateway
ports:
- ${GATEWAY_PORT}:${GATEWAY_PORT}
integrated-account:
image: integrated-account
build:
dockerfile: ./integrated-account/Dockerfile
context: ../
env_file:
- .env
container_name: integrated-account
ports:
- ${ACCOUNT_PORT}:${ACCOUNT_PORT}
integrated-order:
image: integrated-order
build:
dockerfile: ./integrated-order/Dockerfile
context: ../
env_file:
- .env
container_name: integrated-order
ports:
- ${ORDER_PORT}:${ORDER_PORT}
integrated-storage:
image: integrated-storage
build:
dockerfile: ./integrated-storage/Dockerfile
context: ../
env_file:
- .env
container_name: integrated-storage
ports:
- ${STORAGE_PORT}:${STORAGE_PORT}
integrated-praise-provider:
image: integrated-praise-provider
build:
dockerfile: ./integrated-praise-provider/Dockerfile
context: ../
env_file:
- .env
container_name: integrated-praise-provider
ports:
- ${PRAISE_PROVIDER_PORT}:${PRAISE_PROVIDER_PORT}
integrated-praise-consumer:
image: integrated-praise-consumer
build:
dockerfile: ./integrated-praise-consumer/Dockerfile
context: ../
env_file:
- .env
container_name: integrated-praise-consumer
ports:
- ${PRAISE_CONSUMER_PORT}:${PRAISE_CONSUMER_PORT}
depends_on:
- integrated-praise-provider
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/en/docker-compose-deployment.md
================================================
# Spring Cloud Alibaba Containerized Deployment Best Practices | Docker-Compose Edition
## Preparation
If you have not installed Docker or Docker-Compose, please follow the official documentation to build the environment
> Note: When using Docker-Compose to experience the demo, please make sure that the local machine memory resource is >= 24G!
- Docker:https://docs.docker.com/desktop/install/linux-install/
- Docker-Compose:https://docs.docker.com/compose/install/
### Hosts configuration
To ensure that the code can start properly, please configure the local host mapping first, add the following mapping to the configuration file.
```shell
# for integrated-example
127.0.0.1 integrated-mysql
127.0.0.1 nacos-server
127.0.0.1 seata-server
127.0.0.1 rocketmq
127.0.0.1 gateway-service
127.0.0.1 integrated-frontend
```
### Preparing jar packages
Go to the `spring-cloud-alibaba-examples` directory and run the `mvn package` command to compile the project and generate the jar package, so as to prepare for the subsequent construction of the docker service image.
## Quickly start
### Component start
Enter `spring-cloud-alibaba-examples/integration-example` directory, run the following command in the terminal to quickly deploy the components required to run example: `docker-compose -f ./docker-compose/docker-compose-env.yml up -d`.
### Add configuration
After docker-compose-env.yml is run successfully, add the Nacos configuration:
- Enter `spring-cloud-alibaba-examples/integration-example` directory;
- Execute the `config-init/scripts/nacos-config-quick.sh` script file in the terminal.
The one-click import of all micro-service configurations is complete.
> Note: windows operating systems can use `git bash` to execute shell script files to complete the configuration import.
### Service start
Enter `spring-cloud-alibaba-examples/integration-example` directory, Run the following command in the terminal to quickly deploy the services required for running example: `docker-compose -f ./docker-compose/docker-compose-service.yml up -d`.
## Stop all containers
### Stops the service container
Enter `spring-cloud-alibaba-examples/integration-examplee` directory, Run the following command in the terminal to `docker-compose -f ./docker-compose/docker-compose-service.yml down` to stop the running example service container.
### Stops the component container
Enter `spring-cloud-alibaba-examples/integration-example` directory, Run the following command in the terminal to `docker-compose -f ./docker-compose/docker-compose-env.yml down` to stop the running example component container.
> When the container starts, you can observe the startup process of the container through `docker-compose- f docker-compose-*.yml up` !
## Experience Demo
### Distributed Transaction Capabilities
#### Scenario Description
For the distributed transaction capability, we provide the scenario **where a user places an order for goods** and after placing the order.
- First request the inventory module and deduct the inventory
- Deduct the account balance
- Generate order information to return a response
#### Start test
Visit `http://integrated-frontend:8080/order` to experience the corresponding scenario.
By clicking the order button directly to submit the form, we simulate the client sending a request to the gateway to create an order.
- The user's userId is admin
- The item number of the user's order is 1
- The number of items purchased in this order is 1

In this demo example, the unit price of each item is 2 for demonstration purposes.
And in the previous preparation, **initialize business database table** we created a new user userId = admin with a balance of $3, and a new item numbered 1 with 100 units in stock.
So by doing the above, we will create an order, deduct the number of items in stock corresponding to item number 1 (100-1=99), and deduct the balance of the admin user (3-2=1).

If the same interface is requested again, again the inventory is deducted first (99-1=98), but an exception is thrown because the admin user's balance is insufficient and is caught by Seata, which performs a two-stage commit of the distributed transaction and rolls back the transaction.

You can see that the database still has 99 records in stock because of the rollback.
### Fused flow limiting, peak shaving capability
#### Scenario Description
For service fusion limiting and peak and valley cutting in the context of high traffic, we provide a scenario **where users make likes for products**. In this scenario, we provide two ways to deal with high traffic.
- Sentinel binds specified gateway routes on the gateway side for fusion degradation of services.
- RocketMQ performs traffic clipping, where the producer sends messages to RocketMQ under high traffic requests, while the consumer pulls and consumes through a configurable consumption rate, reducing the pressure of high traffic direct requests to the database to increase the number of likes requests.
#### Start test
- Sentinel service meltdown degradation
Visit `http://integrated-frontend:8080/sentinel` to experience the corresponding scenario.

The Gateway routing point service has a flow limit rule of 5, while 10 concurrent requests are simulated on the front end through asynchronous processing.
Therefore, we can see that Sentinel performs a service fusion on the Gateway side to return the fallback to the client for the extra traffic, while the number of likes in the database is updated (+5).

- RocketMQ is performing peak and valley reduction
Visit `http://integrated-frontend:8080/rocketmq` to experience the corresponding scenario.
Since we previously configured the consumption rate and interval of the `integrated-praise-consumer` consumer module in Nacos, we simulate 1000 requests for likes at the click of a button, and the `integrated-praise-provider`
will deliver 1000 requests to the Broker, and the consumer module will consume them according to the configured consumption rate, and update the database with the product data of the likes, simulating the characteristics of RocketMQ to cut the peaks and fill the valleys under high traffic.
You can see that the number of likes in the database is being dynamically updated.

## Other
This example **is just a selection of typical features for each component to serve the application scenario**.
If you are interested or want to go deeper, you are welcome to study the individual example documentation for each component.
- Nacos examples
- [Nacos config example](../../../nacos-example/readme.md)
- [Nacos discovery example](../../../nacos-example/readme.md)
- [Sentinel core example](../../../sentinel-example/README.md)
- [Seata example](../../../seata-example/readme.md)
- [RocketMQ example](../../../rocketmq-example/readme.md)
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/en/kubernetes-deployment.md
================================================
# Spring Cloud Alibaba Containerized Deployment Best Practices | Kubernetes Helm-Chart Edition
## Preparation
This is the Spring Cloud Alibaba (hereinafter referred to as SCA) Best Practices Kubernetes deployment version, which requires you to prepare the following environment.
- Kubernetes (We recommend using Docker Desktop's built-in integrated Kubernetes environment for this experience.)
- Helm
If the test machine does not already have the above environment, please go to the official documentation to build the environment.
- [Helm Installation](https://helm.sh/zh/docs/intro/install/)
- [Kubernetes Docker Desktop Quick Installation](https://docs.docker.com/desktop/kubernetes/)
Here expose the services of the Pod in Kubernetes to the outside world by means of NodePort, and configure the ip mapping of the Kubernetes cluster node before starting the test.
```shell
# Please adjust with the public ip of your K8S node
120.24.xxx.xxx integrated-frontend
120.24.xxx.xxx gateway-service
120.24.xxx.xxx integrated-mysql-web
120.24.xxx.xxx nacos-mysql-web
120.24.xxx.xxx nacos-svc
```
## Start the test
Go to the ``spring-cloud-alibaba-examples/integrated-example`` directory and execute the following command to deploy the application using Helm.
```shell
helm package helm-chart
helm install integrated-example integrated-example-1.0.0.tgz
```
By running the above command, quickly deploy the best practice example through Helm according to the Helm Chart documentation provided by the SCA community.
You can check the deployment status of each container resource through the `kubectl` command provided by Kubernetes, and wait patiently for **all containers to finish starting** to experience the usage scenarios and capabilities of each component on the corresponding page.
If you want to stop the experience, enter the following command.
```shell
helm uninstall integrated-example
```
### Distributed Transaction Capabilities
#### Scenario Description
For the distributed transaction capability, SCA community provide a scenario **where a user places an order to purchase goods** and after placing the order.
- First request the inventory module and deduct the inventory
- Deduct the account balance
- Generate order information to return a response
##### Start test
Visit `http://integrated-frontend:30080/order` to experience the corresponding scenario.
By clicking directly on the order button to submit the form, simulate the client sending a request to the gateway to create an order.
- The user's userId is admin
- The user places an order with item number 1
- The number of items purchased in this order is 1

In this demo example, the unit price of each item is 2 for demonstration purposes.
While initializing the `integrated-mysql` container, **initializing the business database table** creates a new user, the user's userId is admin, with a balance of $3; and a new item numbered 1 with 100 units in stock.
So by doing the above, application will create an order, deduct the number of items in stock corresponding to item number 1 (100-1=99), and deduct the balance of the admin user (3-2=1).

If the same interface is requested again, again the inventory is deducted first (99-1=98), but an exception is thrown because the admin user's balance is insufficient and is caught by Seata, which performs a two-stage commit of the distributed transaction and rolls back the transaction.

You can see that the database still has 99 records in stock because of the rollback.
### Fused flow limiting, peak shaving capability
#### Scenario Description
For service fusion limiting and peak and valley cutting in the context of high traffic, SCA community provide a scenario** where users make likes for products**. In this scenario, we provide two ways to deal with high traffic.
- Sentinel binds specified gateway routes on the gateway side for fusion degradation of services.
- RocketMQ performs traffic clipping, where the producer sends messages to RocketMQ under high traffic requests, while the consumer pulls and consumes through a configurable consumption rate, reducing the pressure of high traffic direct requests to the database to increase the number of likes requests.
#### Startup test
- Sentinel Service Meltdown Degradation
Visit `http://integrated-frontend:30080/sentinel` to experience the corresponding scenario.

The Gateway routing point service has a flow limit rule of 5, while 10 concurrent requests are simulated on the front end through asynchronous processing.
Therefore, we can see that Sentinel performs a service fusion on the Gateway side to return the fallback to the client for the extra traffic, while the number of likes in the database is updated (+5).

- RocketMQ is performing peak and valley reduction
Visit `http://integrated-frontend:30080/rocketmq` to experience the corresponding scenario.

Since the consumption rate and interval of the `integrated-praise-consumer` consumer module is configured in Nacos before, the application will simulate 1000 "like" requests when clicking the button, `integrated-praise-provider`
will deliver 1000 requests to the Broker, and the consumer module will consume them according to the configured consumption rate, and update the database with the product data of the likes, simulating the characteristics of RocketMQ to cut the peaks and fill the valleys under high traffic.
You can see that the number of likes in the database is being dynamically updated.

## Other
This example **is just a selection of typical features for each component to serve the application scenario**.
Of course, there is more to each component than just what is demonstrated in the best practices, so if you are interested or want to go deeper, feel free to read the individual example documentation for each component.
- Nacos examples
- [Nacos config example](../../../nacos-example/readme.md)
- [Nacos discovery example](../../../nacos-example/readme.md)
- [Sentinel core example](../../../sentinel-example/README.md)
- [Seata example](../../../seata-example/readme.md)
- [RocketMQ example](../../../rocketmq-example/readme.md)
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/en/local-deployment.md
================================================
# Spring Cloud Alibaba Containerized Deployment Best Practices | Local Deployment Edition
## Preparation
### Environment Declaration
Before running the local example, you need to ensure that the local machine has the following basic environment. If you do not have the current local environment, the following steps to demonstrate the construction process.
You can also quickly launch the component through the docker-compose file provided by the Spring Cloud Alibaba (SCA) community.
- Nacos server
- Seata server
- RocketMQ server
- MySQL server
### Component Service Versions
For each component version of this project, please go to the release page of each community to download and decompression run.
- [Nacos: version 2.1.0](https://github.com/alibaba/nacos/releases)
- [Seata: version 1.5.1](https://github.com/seata/seata/releases)
- [RocketMQ: version 4.9.4](https://github.com/apache/rocketmq/releases)
- MySQL: version 5.7
### Hosts configuration
To ensure that the code can start properly, please configure the local host mapping first, add the following mapping to the configuration file.
```shell
# for integrated-example
127.0.0.1 integrated-mysql
127.0.0.1 nacos-server
127.0.0.1 seata-server
127.0.0.1 rocketmq
127.0.0.1 gateway-service
127.0.0.1 integrated-frontend
```
### Database configuration
Before you start the database configuration, please make sure the MySQL server is on.
#### Initialize business tables
For the first scenario, the order, account, and inventory microservices all need their own databases, while the second scenario simulates a database for storing like information as well.
Run the sql script `spring-cloud-alibaba-examples/integrated-example/config-init/sql/init.sql` to create the environment required for the business and the Seata-related tables in one click.
### Nacos Configuration
At this point, the database services are configured and you need to configure the Nacos configuration center for all the microservice configuration files.
#### Nacos startup
For the sake of example, here we use the ``standalone`` mode of Nacos, go to the unpacked directory of Nacos and execute the following command.
```shell
#Linux/Mac environment
sh bin/startup.sh -m standalone
#If you are in Ubuntu and the above command gives you an error [[symbol not found, you can run the following command
bash bin/startup.sh -m standalone
#Win environment
. \bin\startup.cmd -m standalone
````
#### Adding configuration files
Before bulk importing the configuration, please modify the datasource configuration (username and password) in `spring-cloud-alibaba-examples/integrated-example/config-init/config/datasource-config.yaml`.
After that, run `spring-cloud-alibaba-examples/integrated-example/config/scripts/nacos-config-quick.sh` to complete the one-click import of all microservice configurations.
```shell
# linux
sh nacos-config-quick.sh
# windows can use git bash to import the configuration, run the command as above
```
### Seata Configuration
After the Nacos service registry and configuration center are deployed, here is the configuration of the Seata server.
Seata's db mode requires additional configuration of database information and modification of the Seata Server configuration file, and the configuration file has been merged in the new version compared to the old version, so for demonstration purposes, Seata Server is started in `file` mode on Seata standalone.
#### Start Seata Server
Go to the seata directory after the release and execute the following command.
```shell
#Linux/Mac environment
sh . /bin/seata-server.sh
#Win environment
bin\seata-server.bat
```
### RocketMQ configuration
After the Seata service starts, you can start the RocketMQ NameServer and Broker services.
Go to the unpacked rocketmq directory after the release and execute the following command.
#### Start the NameServer
```shell
#Linux/Mac environment
sh bin/mqnamesrv
#Win environment
. \bin\mqnamesrv.cmd
```
#### Start Broker
```shell
#Linux/Mac environment
sh bin/mqbroker
#Win environment
. \bin\mqbroker.cmd
```
## Run the demo example
After the preparation work is done, you can run the demo, mainly according to different usage scenarios, you can experience the user order (distributed transaction capability) and simulate the high traffic point (meltdown and limit the flow as well as the ability to cut the peak and fill the valley) respectively.
First, you need to start the `integrated-frontend` and `integrated-gateway` projects separately.
- `integrated-frontend` module is front page for best practice examples.
- `integral-gateway` module is the gateway for the entire best practice example.
### Distributed Transaction Capabilities
#### Scenario Description
For the distributed transaction capability, we provide the scenario **where a user places an order for goods** and after placing the order.
- First request the inventory module and deduct the inventory
- Deduct the account balance
- Generate order information to return a response
##### Start test
Start `integrated-storage`,`integrated-account`,`integrated-order` microservices respectively.
Visit `http://integrated-frontend:8080/order` to experience the corresponding scenario.
By clicking the order button directly to submit the form, application simulate the client sending a request to the gateway to create an order.
- The user's userId is admin
- The item number of the user's order is 1
- The number of items purchased in this order is 1

In this demo example, the unit price of each item is 2 for demonstration purposes.
And in the previous preparation, **initialize business database table** application created a new user, the user's userId is admin with a balance of $3, and a new item numbered 1 with 100 units in stock.
So by doing the above, we will create an order, deduct the number of items in stock corresponding to item number 1 (100-1=99), and deduct the balance of the admin user (3-2=1).

If the same interface is requested again, again the inventory is deducted first (99-1=98), but an exception is thrown because the admin user's balance is insufficient and is caught by Seata, which performs a two-stage commit of the distributed transaction and rolls back the transaction.

You can see that the database still has 99 records in stock because of the rollback.
### Fused flow limiting, peak shaving capability
#### Scenario Description
For service fusion limiting and peak and valley cutting in the context of high traffic, SCA community provide a scenario **where users make likes for products**. In this scenario, we provide two ways to deal with high traffic.
- Sentinel binds specified gateway routes on the gateway side for fusion degradation of services.
- RocketMQ performs traffic clipping, where the producer sends messages to RocketMQ under high traffic requests, while the consumer pulls and consumes through a configurable consumption rate, reducing the pressure of high traffic direct requests to the database to increase the number of likes requests.
#### Startup test
Start the `integrated-praise-provider` and `integrated-praise-consumer` modules separately.
- Sentinel service meltdown degradation
Visit `http://integrated-frontend:8080/sentinel` to experience the corresponding scenario.

The Gateway routing point service has a flow limit rule of 5, while 10 concurrent requests are simulated on the front end through asynchronous processing.
Therefore, we can see that Sentinel performs a service fusion on the Gateway side to return the fallback to the client for the extra traffic, while the number of likes in the database is updated (+5).

- RocketMQ is performing peak and valley reduction
Visit `http://integrated-frontend:8080/rocketmq` to experience the corresponding scenario.
Since previously configured the consumption rate and interval of the `integrated-praise-consumer` consumer module in Nacos, simulate 1000 requests for likes at the click of a button, and the `integrated-praise-provider`
will deliver 1000 requests to the Broker, and the consumer module will consume them according to the configured consumption rate, and update the database with the product data of the likes, simulating the characteristics of RocketMQ to cut the peaks and fill the valleys under high traffic.
You can see that the number of likes in the database is being dynamically updated.

## Other
This example **is just a selection of typical features for each component to serve the application scenario**.
If you are interested or want to go deeper, you are welcome to study the individual example documentation for each component.
- Nacos examples
- [Nacos config example](../../../nacos-example/readme.md)
- [Nacos discovery example](../../../nacos-example/readme.md)
- [Sentinel core example](../../../sentinel-example/README.md)
- [Seata example](../../../seata-example/readme.md)
- [RocketMQ example](../../../rocketmq-example/readme.md)
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/en/readme.md
================================================
# Integrated Example
## Project Description
This project is a demo of Spring Cloud Alibaba (hereinafter referred to as SCA) containerized deployment best practices, and is an example project integrating SCA components (Nacos, Sentinel, Seata, RocketMQ).
The main components used and their usage features are as follows.
- Spring Cloud Gateway: gateway
- Nacos: configuration centre and service registry
- Sentinel: fusion flow limiting
- Seata: Distributed Transactions
- RocketMQ: message queues for peak and valley reduction
- Docker: Microservices Containerized Deployment
- Kubernetes Helm Chart

## Application Scenario Description
In this demo, SCA community provide two business scenarios.
1) A scenario where a user places an order for goods and after placing the order.
- First request the inventory module to deduct the inventory
- Deduct the account balance
- Generate order information and return a response
2) The user likes the goods (simulating the producer-consumer application scenario of MQ) and returns the details (number of likes, etc.) after the goods have been liked.
### Detailed description of the component
1) In which the scenario where the user places an order for the goods mainly uses Seata to perform distributed transactions to represent the capabilities.
2) The scenario where the user likes a product simulates a high traffic environment with Sentinel for flow limiting or RocketMQ for peak shaving. In this scenario, SCA community provide two ways to deal with high traffic.
- Sentinel binds a specified gateway route on the gateway side for service fusion degradation.
- RocketMQ performs peak-shaving, where producers send messages to RocketMQ and consumers pull and consume at configurable consumption rates, reducing the pressure of high traffic direct requests to the database and increasing the number of likes.
#### Spring Cloud Gateway
A gateway to the microservices module.
Spring Cloud GateWay integrates with Nacos, enabling dynamic routing configuration.
By listening for changes to the Nacos configuration, the service gateway routing configuration is dynamically refreshed so that each time the routing information changes, there is no need to modify the configuration file and then restart the service.
#### Nacos
The configuration centre for each microservice, the service registry.
- Configuration Centre
- Shared configuration: MySQL data source related information configuration.
- Registration Centre
- All microservice modules are registered to Nacos for service registration and discovery.
- Integration with Spring Cloud Gateway gateway.
#### Seata
Seata-based AT model for distributed transaction processing for the Inventory, Accounts and Orders modules.
Roll back transactions whenever stock is low/account balance is low.
#### Sentinel
Service fusion flow limiting for point and click scenarios.
Integrates Nacos Configuration Center with Spring Cloud Gateway to enable dynamic configuration of fused flow limiting rules for specified routing rules.
#### RocketMQ
Used for peaks and valleys reduction of like service traffic.
By sending high volume like requests from the producer to the mq, the consumer module pulls from the mq and consumes them with a certain frequency, rather than simply fusing and limiting the degradation of the service directly, enabling RocketMQ's ability to shave peaks and valleys for high volume traffic.
## Release Notes
This project provides a [local-deployment](local-deployment.md), [docker-compose version](docker-compose-deployment.md) and a [Kubernetes Helm-Chart version](kubernetes-deployment.md).
- To learn how to configure the components and build the complete environment, we recommend learning the [local-deployment](local-deployment.md).
- If you only want to run the sample code, avoid the tedious local environment construction process, and do not want to use the K8S cluster. You can try using [docker-compose version] (docker-compose-deployment.md).
- If you want to quickly experience the components on a K8S cluster and skip the process of deploying each component, please check out the [Kubernetes Helm-Chart version](kubernetes-deployment.md).
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/zh/docker-compose-deploy-zh.md
================================================
# Spring Cloud Alibaba 容器化部署最佳实践 | Docker-Compose 版本
## 准备工作
> Note: 使用 Docker-Compose 方式体验 Demo 时,请确保本地机器内存资源 >= 24G!
如果您还没有安装 Docker 和 Docker-Compose,请按照官方文档来构建运行环境:
- Docker:https://docs.docker.com/desktop/install/linux-install/
- Docker-Compose:https://docs.docker.com/compose/install/
### Hosts 配置
为确保代码能够正常启动,请先配置本地主机映射,将以下映射添加到配置文件中。
```shell
# for integrated-example
127.0.0.1 integrated-mysql
127.0.0.1 nacos-server
127.0.0.1 seata-server
127.0.0.1 rocketmq
127.0.0.1 gateway-service
127.0.0.1 integrated-frontend
```
### 准备 jar 包
进入 `spring-cloud-alibaba-examples` 目录下,执行 `mvn package` 命令编译项目生成 jar 包,为后续 Docker 构建服务镜像做准备。
## 快速启动
### 组件启动
进入 `spring-cloud-alibaba-examples/integrated-example` 目录下,在终端中执行以下命令 `docker-compose -f ./docker-compose/docker-compose-env.yml up -d` 来快速部署运行 example 所需组件。
### 添加配置
docker-compose-env.yml 文件运行成功之后,添加 Nacos 配置:
1. 进入 `spring-cloud-alibaba-examples/integrated-example` 目录下;
2. 在终端中执行 `config-init/scripts/nacos-config-quick.sh` 脚本文件。
完成所有微服务配置的一键导入。
> 注意:windows 操作系统可以通过 `git bash` 执行 shell 脚本文件完成配置导入。
### 服务启动
进入 `spring-cloud-alibaba-examples/integrated-example` 目录下,在终端中执行以下命令 `docker-compose -f ./docker-compose/docker-compose-service.yml up -d` 来快速部署运行 example 所需服务。
## 停止所有容器
### 停止服务容器
进入 `spring-cloud-alibaba-examples/integrated-example` 目录下,在终端中执行以下命令 `docker-compose -f ./docker-compose/docker-compose-service.yml down` 来停止正在运行的 example 服务容器。
### 停止组件容器
进入 `spring-cloud-alibaba-examples/integrated-example` 目录下,在终端中执行以下命令 `docker-compose -f ./docker-compose/docker-compose-env.yml down` 来停止正在运行的 example 组件容器。
> 在容器启动时,可以通过 `docker-compose -f docker-compose-*.yml up` 观察容器的启动过程!
## 体验 Demo
### 分布式事务能力
#### 场景说明
针对分布式事务能力,SCA 社区提供了**用户下单购买货物的场景**,下单后:
- 先请求库存模块,扣减库存
- 扣减账户余额
- 生成订单信息返回响应
#### 启动测试
访问 `http://integrated-frontend:8080/order` 来体验对应场景。
直接点击下单按钮提交表单,应用模拟客户端向网关发送了一个创建订单的请求。
- 用户的 userId 为 admin
- 用户下单的商品编号为1号
- 此次订单购买的商品个数为1个

在本 demo 示例中,为了便于演示,每件商品的单价都为2。
而在前面的准备工作中,**初始化业务数据库表**的时候应用新建了一个用户,用户 userId 为 admin,余额为 3 元;同时新建了一个编号为 1 号的商品,库存为 100 件。
因此通过上述的操作,应用会创建一个订单,扣减对应商品编号为 1 号的库存个数(100-1=99),扣减 admin 用户的余额(3-2=1)。

如果再次请求相同的接口,同样是先扣减库存(99-1=98),但是会因为 admin 用户余额不足而抛出异常,并被 Seata 捕获,执行分布式事务二阶段提交,回滚事务。

可以看到数据库中库存的记录因为回滚之后仍然为 99 件。
### 熔断限流,削峰填谷能力
#### 场景说明
针对大流量背景下的服务熔断限流,削峰填谷,SCA 社区提供了**用户为商品进行点赞的场景**。在此场景下,SCA 社区提供了两种应对大流量的处理方式。
- Sentinel 在网关侧绑定指定网关路由进行服务的熔断降级。
- RocketMQ 进行流量削峰填谷,在大流量请求下,生产者向 RocketMQ 发送消息,而消费者则通过可配置的消费速率进行拉取消费,减少大流量直接请求数据库增加点赞请求的压力。
#### 启动测试
- Sentinel 服务熔断降级
访问 `http://integrated-frontend:8080/sentinel` 体验对应场景。

网关路由点赞服务的限流规则为 5,而在前端通过异步处理模拟了 10 次并发请求。
因此可以看到 Sentinel 在 Gateway 侧针对多出的流量进行了服务熔断返回 fallback 给客户端,同时数据库的点赞数进行了更新(+5)。

- RocketMQ 进行流量削峰填谷
访问 `http://integrated-frontend:8080/rocketmq` 体验对应场景。
由于之前在 Nacos 中配置了 `integrated-praise-consumer` 消费者模块的消费速率以及间隔,在点击按钮时应用模拟 1000 个点赞请求,针对 1000 个点赞请求,`integrated-praise-provider`
会将 1000 次请求都向 Broker 投递消息,而在消费者模块中会根据配置的消费速率进行消费,向数据库更新点赞的商品数据,模拟大流量下 RocketMQ 削峰填谷的特性。
可以看到数据库中点赞的个数正在动态更新。

## 其他
本示例**仅是针对各个组件选取出了较为典型的功能特性来服务应用场景**
当然各个组件的功能特性不仅仅只包含最佳实践中演示的这些,如果您感兴趣或是想要深入了解,欢迎学习各个组件的独立 example 相关文档。
- Nacos examples
- [Nacos config example](../../../nacos-example/readme.md)
- [Nacos discovery example](../../../nacos-example/readme.md)
- [Sentinel core example](../../../sentinel-example/README-zh.md)
- [Seata example](../../../seata-example/readme.md)
- [RocketMQ example](../../../rocketmq-example/readme.md)
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/zh/kubernetes-deployment-zh.md
================================================
# Spring Cloud Alibaba容器化部署最佳实践 | Kubernetes Helm-Chart 版本
## 准备工作
此版本为 Spring Cloud Alibaba (后文简称为SCA)最佳实践 Kubernetes 部署版本,运行示例需要准备如下环境:
- Kubernetes(建议使用 Docker Desktop 内置集成的 Kubernetes 环境进行体验。)
- Helm
如果测试机器上还未具备如上环境,请移步至对应官方文档进行环境搭建。
- [Helm 安装](https://helm.sh/zh/docs/intro/install/)
- [Kubernetes Docker Desktop 快捷安装](https://docs.docker.com/desktop/kubernetes/)
在这里通过 NodePort 的方式来向外界暴露 Kubernetes 中 Pod 的服务,在启动测试前还需配置好 Kubernetes 集群节点的 ip 映射。
```sh
# 实际情况请结合您的 K8S 节点的公网 ip 进行调整
120.24.xxx.xxx integrated-frontend
120.24.xxx.xxx gateway-service
120.24.xxx.xxx integrated-mysql-web
120.24.xxx.xxx nacos-mysql-web
120.24.xxx.xxx nacos-svc
```
## 启动测试
进入到 `spring-cloud-alibaba-examples/integrated-example` 目录下,执行如下命令利用 Helm 部署应用程序。
```shell
helm package helm-chart
helm install integrated-example integrated-example-1.0.0.tgz
```
通过运行上述命令,根据SCA社区提供的 Helm Chart 文档通过 Helm 快速完成最佳实践示例的部署。
可以通过 Kubernetes 提供的 `kubectl` 命令查看各容器资源部署的情况,耐心等待**所有容器完成启动后**即可到对应页面体验各个组件的使用场景及能力。
如果您想停止体验,输入如下命令。
```shell
helm uninstall integrated-example
```
### 分布式事务能力
#### 场景说明
针对分布式事务能力,SCA社区提供了**用户下单购买货物的场景**,下单后:
- 先请求库存模块,扣减库存
- 扣减账户余额
- 生成订单信息返回响应
##### 启动测试
访问 `http://integrated-frontend:30080/order` 来体验对应场景。
直接点击下单按钮提交表单,模拟客户端向网关发送了一个创建订单的请求。
- 用户的 userId 为 admin
- 用户下单的商品编号为1号
- 此次订单购买的商品个数为1个

在本 demo 示例中,为了便于演示,每件商品的单价都为2。
而在 `integrated-mysql` 容器的初始化时,**初始化业务数据库表**的时候新建了一个用户,用户的userId为admin,余额为 3 元;同时新建了一个编号为 1 号的商品,库存为 100 件。
因此通过上述的操作,应用会创建一个订单,扣减对应商品编号为 1 号的库存个数(100-1=99),扣减 admin 用户的余额(3-2=1)。

如果再次请求相同的接口,同样是先扣减库存(99-1=98),但是会因为 admin 用户余额不足而抛出异常,并被 Seata 捕获,执行分布式事务二阶段提交,回滚事务。

可以看到数据库中库存的记录因为回滚之后仍然为 99 件。
### 熔断限流,削峰填谷能力
#### 场景说明
针对大流量背景下的服务熔断限流,削峰填谷,SCA社区提供了**用户为商品进行点赞的场景**。在此场景下,SCA社区提供了两种应对大流量的处理方式。
- Sentinel 在网关侧绑定指定网关路由进行服务的熔断降级。
- RocketMQ 进行流量削峰填谷,在大流量请求下,生产者向 RocketMQ 发送消息,而消费者则通过可配置的消费速率进行拉取消费,减少大流量直接请求数据库增加点赞请求的压力。
#### 启动测试
- Sentinel 服务熔断降级
访问 `http://integrated-frontend:30080/sentinel` 体验对应场景。

网关路由点赞服务的限流规则为 5,而在前端通过异步处理模拟了 10 次并发请求。
因此可以看到 Sentinel 在 Gateway 侧针对多出的流量进行了服务熔断返回 fallback 给客户端,同时数据库的点赞数进行了更新(+5)。

- RocketMQ 进行流量削峰填谷
访问 `http://integrated-frontend:30080/rocketmq` 体验对应场景。

由于之前在 Nacos 中配置了 `integrated-praise-consumer` 消费者模块的消费速率以及间隔,在点击按钮时应用将会模拟 1000 个点赞请求,针对 1000 个点赞请求,`integrated-praise-provider`
会将 1000 次请求都向 Broker 投递消息,而在消费者模块中会根据配置的消费速率进行消费,向数据库更新点赞的商品数据,模拟大流量下 RocketMQ 削峰填谷的特性。
可以看到数据库中点赞的个数正在动态更新。

## 其他
本示例**仅是针对各个组件选取出了较为典型的功能特性来服务应用场景**。
当然各个组件的功能特性不仅仅只包含最佳实践中演示的这些,如果您对SCA感兴趣或是想要深入了解SCA项目,欢迎阅览各个组件的独立 example 相关文档。
- Nacos examples
- [Nacos config example](../../../nacos-example/readme.md)
- [Nacos discovery example](../../../nacos-example/readme.md)
- [Sentinel core example](../../../sentinel-example/README-zh.md)
- [Seata example](../../../seata-example/readme.md)
- [RocketMQ example](../../../rocketmq-example/readme.md)
-
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/zh/local-deployment-zh.md
================================================
# Spring Cloud Alibaba 容器化部署最佳实践 | 本地部署版本
## 准备工作
### 环境声明
在运行本地示例之前,需要保证本机具备以下的基础环境,如果您的本地没有当前的环境,下面会一步步进行搭建,演示搭建过程。
当然您也可以通过 Spring Cloud Alibaba (下文简称为SCA)社区提供的docker-compose文件快速启动相应组件。
- Nacos 服务端
- Seata 服务端
- RocketMQ 服务端
- MySQL 服务端
### 组件服务版本
本项目的各个组件版本请移步至各个社区的 release 页面进行下载并解压运行。
- [Nacos: 2.1.0 版本](https://github.com/alibaba/nacos/releases)
- [Seata: 1.5.1 版本](https://github.com/seata/seata/releases)
- [RocketMQ: 4.9.4 版本](https://github.com/apache/rocketmq/releases)
- MySQL: 5.7 版本
### Hosts配置
为了保证代码可以正常启动,请先配置好本机的 host 映射,在配置文件中新增如下的映射。
```shell
# for integrated-example
127.0.0.1 integrated-mysql
127.0.0.1 nacos-server
127.0.0.1 seata-server
127.0.0.1 rocketmq
127.0.0.1 gateway-service
127.0.0.1 integrated-frontend
```
### 数据库配置
下面开始本地环境搭建准备,在数据库配置开始之前,请确保 MySQL 的服务端开启。
#### 初始化业务表
针对第一个场景,订单、账户、库存微服务都需要各自的数据库,而第二个场景模拟点赞也需要存储点赞信息的数据库。
运行 `spring-cloud-alibaba-examples/integrated-example/config-init/sql/init.sql` 的 sql 脚本一键创建业务所需的环境以及 Seata 相关的表。
### Nacos配置
至此,数据库的服务配置完毕,下面需要配置 Nacos 的配置中心有关所有的微服务配置文件。
#### Nacos启动
为了便于 example 的演示,这里采用 Nacos 的 `standalone` 模式启动,进入到 Nacos 解压后的目录下,执行如下命令。
```shell
#Linux/Mac环境
sh bin/startup.sh -m standalone
#如果您是Ubuntu环境,执行上述命令启动报错提示[[符号找不到,可以执行如下的命令
bash bin/startup.sh -m standalone
#Win环境
.\bin\startup.cmd -m standalone
```
#### 新增配置文件
在批量导入配置之前,请先修改 `spring-cloud-alibaba-examples/integrated-example/config-init/config/datasource-config.yaml` 中的数据源配置**(用户名和密码)**。
之后运行 `spring-cloud-alibaba-examples/integrated-example/config-init/scripts/nacos-config-quick.sh` 来完成所有微服务配置的一键导入。
```shell
# linux
sh nacos-config-quick.sh
# windows 可以使用git bash来完成配置的导入 执行命令同上
```
### Seata 配置
Nacos 服务注册中心以及配置中心部署完毕之后,下面是 Seata 服务端的配置。
Seata 的 db 模式需要额外配置数据库信息以及修改 Seata 服务端的配置文件,且在新版本中配置文件相较于旧版本进行了合并,因此这里为了便于演示方便,采用 Seata 单机的`file`模式启动 Seata Server。
#### 启动 Seata Server
进入到 release 解压后的 seata 目录中,执行如下命令。
```shell
#Linux/Mac环境
sh ./bin/seata-server.sh
#Win环境
bin\seata-server.bat
```
### RocketMQ 配置
Seata 服务启动后可以启动 RocketMQ 的 NameServer 以及 Broker 服务。
进入到 release 解压后的 rocketmq 目录中,执行如下命令。
#### 启动 NameServer
```shell
#Linux/Mac环境
sh bin/mqnamesrv
#Win环境
.\bin\mqnamesrv.cmd
```
#### 启动 Broker
```shell
#Linux/Mac环境
sh bin/mqbroker
#Win环境
.\bin\mqbroker.cmd -n localhost:9876
```
## 运行 Demo 示例
准备工作完成后可以运行 demo 示例,主要根据不同的使用场景,可以分别体验用户下单(分布式事务能力)以及模拟高流量点赞(熔断限流以及削峰填谷的能力)。
首先需要分别启动 `integrated-frontend` 以及 `integrated-gateway` 微服务应用。
- `integrated-gateway` 模块是整个最佳实践示例的网关。
- `integrated-frontend` 为最佳实践示例的简易前端页面。
### 分布式事务能力
#### 场景说明
针对分布式事务能力,SCA社区提供了**用户下单购买货物的场景**,下单后:
- 先请求库存模块,扣减库存
- 扣减账户余额
- 生成订单信息返回响应
##### 启动测试
分别启动 `integrated-storage`,`integrated-account`,`integrated-order` 三个微服务应用。
访问 `http://integrated-frontend:8080/order` 来体验对应场景。
直接点击下单按钮提交表单,应用模拟客户端向网关发送了一个创建订单的请求。
- 用户的 userId 为 admin
- 用户下单的商品编号为1号
- 此次订单购买的商品个数为1个

在本 demo 示例中,为了便于演示,每件商品的单价都为2。
而在前面的准备工作中,**初始化业务数据库表**的时候应用新建了一个用户,用户userId 为 admin,余额为 3 元;同时新建了一个编号为 1 号的商品,库存为 100 件。
因此通过上述的操作,应用会创建一个订单,扣减对应商品编号为 1 号的库存个数(100-1=99),扣减 admin 用户的余额(3-2=1)。

如果再次请求相同的接口,同样是先扣减库存(99-1=98),但是会因为 admin 用户余额不足而抛出异常,并被 Seata 捕获,执行分布式事务二阶段提交,回滚事务。

可以看到数据库中库存的记录因为回滚之后仍然为 99 件。
### 熔断限流,削峰填谷能力
#### 场景说明
针对大流量背景下的服务熔断限流,削峰填谷,SCA社区提供了**用户为商品进行点赞的场景**。在此场景下,SCA社区提供了两种应对大流量的处理方式。
- Sentinel 在网关侧绑定指定网关路由进行服务的熔断降级。
- RocketMQ 进行流量削峰填谷,在大流量请求下,生产者向 RocketMQ 发送消息,而消费者则通过可配置的消费速率进行拉取消费,减少大流量直接请求数据库增加点赞请求的压力。
#### 启动测试
分别启动 `integrated-praise-provider` 以及 `integrated-praise-consumer` 模块。
- Sentinel 服务熔断降级
访问 `http://integrated-frontend:8080/sentinel` 体验对应场景。

网关路由点赞服务的限流规则为 5,而在前端通过异步处理模拟了 10 次并发请求。
因此可以看到 Sentinel 在 Gateway 侧针对多出的流量进行了服务熔断返回 fallback 给客户端,同时数据库的点赞数进行了更新(+5)。

- RocketMQ 进行流量削峰填谷
访问 `http://integrated-frontend:8080/rocketmq` 体验对应场景。
由于之前在 Nacos 中配置了 `integrated-praise-consumer` 消费者模块的消费速率以及间隔,在点击按钮时应用模拟 1000 个点赞请求,针对 1000 个点赞请求,`integrated-praise-provider`
会将 1000 次请求都向 Broker 投递消息,而在消费者模块中会根据配置的消费速率进行消费,向数据库更新点赞的商品数据,模拟大流量下 RocketMQ 削峰填谷的特性。
可以看到数据库中点赞的个数正在动态更新。

## 其他
本示例**仅是针对各个组件选取出了较为典型的功能特性来服务应用场景**
当然各个组件的功能特性不仅仅只包含最佳实践中演示的这些,如果您感兴趣或是想要深入了解,欢迎学习各个组件的独立 example 相关文档。
- Nacos examples
- [Nacos config example](../../../nacos-example/readme.md)
- [Nacos discovery example](../../../nacos-example/readme.md)
- [Sentinel core example](../../../sentinel-example/README-zh.md)
- [Seata example](../../../seata-example/readme.md)
- [RocketMQ example](../../../rocketmq-example/readme.md)
-
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/docs/zh/readme-zh.md
================================================
# Integrated Example
## 项目说明
本项目为 Spring Cloud Alibaba (后文简称为 SCA)容器化部署最佳实践的 Demo 演示项目,是整合了 SCA 相关组件(Nacos, Sentinel, Seata, RocketMQ)的 Example 示例项目。
主要使用的组件及及其使用特性如下:
- Spring Cloud Gateway 网关
- Nacos 配置中心和服务注册中心
- Sentinel 熔断限流
- Seata 分布式事务
- RocketMQ 消息队列削峰填谷
- Docker 微服务容器化部署
- Kubernetes Helm Chart

## 应用场景说明
在本 demo 示例中,SCA 社区提供了两种业务场景。
1) 用户下单购买货物的场景,下单后:
- 先请求库存模块,扣减库存
- 扣减账户余额
- 生成订单信息返回响应
2) 用户为商品进行点赞(模拟 MQ 的生产者消费者应用场景)返回商品点赞后的详细信息(点赞数等)。
### 组件详细说明
1) 其中,用户下单购买货物的场景主要使用 Seata 来进行分布式事务的能力体现。
2) 用户为商品进行点赞的场景,模拟大流量环境下通过 Sentinel 进行限流或是 RocketMQ 进行削峰填谷。在此场景下,SCA社区提供了两种应对大流量的处理方式:
- Sentinel 在网关侧绑定指定网关路由进行服务的熔断降级。
- RocketMQ 进行流量削峰填谷,在大流量请求下,生产者向 RocketMQ 发送消息,而消费者则通过可配置的消费速率进行拉取消费,减少大流量直接请求数据库增加点赞请求的压力。
#### Spring Cloud Gateway
微服务模块的网关。
Spring Cloud GateWay 整合 Nacos,实现动态路由配置。
通过监听 Nacos 配置的改变,实现服务网关路由配置动态刷新,每次路由信息变更,无需修改配置文件而后重启服务。
#### Nacos
各个微服务的配置中心,服务注册中心。
- 配置中心
- 共享配置:MySQL 数据源相关信息配置。
- 注册中心
- 所有的微服务模块都注册到 Nacos 中进行服务注册与发现。
- 整合 Spring Cloud Gateway 网关。
#### Seata
基于 Seata 的 AT 模式,用于库存模块,账户模块,订单模块的分布式事务处理。
只要库存不足/账户余额不足,回滚事务。
#### Sentinel
用于点赞场景的服务熔断限流。
整合 Nacos 配置中心与 Spring Cloud Gateway,实现指定路由规则熔断限流规则动态配置。
#### RocketMQ
用于进行点赞服务流量的削峰填谷。
通过将大流量的点赞请求从生产者发送到 mq,消费者模块从 mq 中拉取进行一定频率的消费,不是简单的直接服务熔断限流降级,实现 RocketMQ 针对大流量的削峰填谷能力。
## 版本说明
本项目提供了[本地部署运行版本](local-deployment-zh.md)、[docker-compose 版本](docker-compose-deploy-zh.md)以及 [Kubernetes Helm-Chart 版本](kubernetes-deployment-zh.md)。
- 如果想要了解具体如何配置各项组件以及完整环境搭建,推荐学习[本地部署运行版本](local-deployment-zh.md)。
- 如果只想运行示例代码,避免繁琐的本地环境搭建过程,又不想使用 k8s 集群。您可以尝试使用 [docker-compose 版本](docker-compose-deploy-zh.md)。
- 如果想要在 K8S 集群上快速体验组件效果,跳过各个组件环境部署等过程,请查看 [Kubernetes Helm-Chart 版本](kubernetes-deployment-zh.md)。
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/Chart.yaml
================================================
apiVersion: v1
appVersion: '1.0'
description: Spring Cloud Alibaba Best Practice Example
name: integrated-example
version: 1.0.0
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-account.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-account
spec:
replicas: 1
selector:
matchLabels:
app: integrated-account
template:
metadata:
labels:
appName: integrated-account
app: integrated-account
spec:
containers:
- name: integrated-account
image: "{{ .Values.image.repository }}integrated-account"
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8012
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-frontend.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: integrated-frontend
labels:
app: integrated-frontend
spec:
type: NodePort
ports:
- port: 8080
name: web
targetPort: 8080
nodePort: 30080
selector:
app: integrated-frontend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-frontend
spec:
replicas: 1
selector:
matchLabels:
app: integrated-frontend
template:
metadata:
labels:
appName: integrated-frontend
app: integrated-frontend
spec:
containers:
- name: integrated-frontend
image: "{{ .Values.image.repository }}integrated-frontend"
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8080
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-gateway.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: gateway-service
labels:
app: integrated-gateway
spec:
type: NodePort
ports:
- port: 30010
name: server
targetPort: 30010
nodePort: 30010
selector:
app: integrated-gateway
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-gateway
spec:
replicas: 1
selector:
matchLabels:
app: integrated-gateway
template:
metadata:
labels:
appName: integrated-gateway
app: integrated-gateway
spec:
containers:
- name: integrated-gateway
image: "{{ .Values.image.repository }}integrated-gateway"
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 30010
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-mysql.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: integrated-mysql-web
spec:
ports:
- name: integrated-mysql-port
protocol: TCP
port: 3306
targetPort: 3306
nodePort: 30306
type: NodePort
selector:
app: integrated-mysql
---
apiVersion: v1
kind: Service
metadata:
name: integrated-mysql
labels:
app: integrated-mysql
spec:
type: ClusterIP
ports:
- port: 3306
name: 'server'
selector:
app: integrated-mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-mysql
spec:
selector:
matchLabels:
app: integrated-mysql
replicas: 1
template:
metadata:
labels:
app: integrated-mysql
spec:
containers:
- name: integrated-mysql
image: '{{ .Values.image.repository }}integrated-mysql'
imagePullPolicy: Always
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
ports:
- containerPort: 3306
protocol: TCP
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-nacos-mysql.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: nacos-mysql
labels:
name: nacos-mysql
spec:
replicas: 1
selector:
matchLabels:
name: nacos-mysql
template:
metadata:
labels:
name: nacos-mysql
spec:
containers:
- name: mysql
image: registry.cn-hangzhou.aliyuncs.com/sca-community/integrated-nacos-mysql
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: 'root'
- name: MYSQL_DATABASE
value: 'nacos_config'
- name: MYSQL_USER
value: 'nacos'
- name: MYSQL_PASSWORD
value: 'nacos'
---
apiVersion: v1
kind: Service
metadata:
name: nacos-mysql
labels:
name: nacos-mysql
spec:
ports:
- port: 3307
targetPort: 3306
selector:
name: nacos-mysql
---
apiVersion: v1
kind: Service
metadata:
name: nacos-mysql-web
spec:
ports:
- name: nacos-mysql-port
protocol: TCP
port: 3307
targetPort: 3306
nodePort: 30307
type: NodePort
selector:
name: nacos-mysql
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-nacos-stand.yaml
================================================
---
apiVersion: v1
kind: Service
metadata:
name: nacos-svc
labels:
app: nacos-svc
spec:
type: NodePort
ports:
- port: 8848
name: server
targetPort: 8848
nodePort: 30848
selector:
app: nacos-standalone
---
apiVersion: v1
kind: Service
metadata:
name: nacos-server
labels:
app: nacos-server
spec:
type: ClusterIP
ports:
- port: 8848
name: server
targetPort: 8848
- port: 9848
name: client-rpc
targetPort: 9848
- port: 9849
name: raft-rpc
targetPort: 9849
- port: 7848
name: old-raft-rpc
targetPort: 7848
selector:
app: nacos-standalone
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nacos-cm
data:
mysql.host: "nacos-mysql"
mysql.db.name: "nacos_config"
mysql.port: "3307"
mysql.user: "nacos"
mysql.password: "nacos"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nacos-standalone
spec:
replicas: 1
template:
metadata:
labels:
app: nacos-standalone
annotations:
pod.alpha.kubernetes.io/initialized: "true"
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- nacos-standalone
topologyKey: "kubernetes.io/hostname"
containers:
- name: local-nacos
imagePullPolicy: Always
image: registry.cn-hangzhou.aliyuncs.com/sca-community/nacos-server
ports:
- containerPort: 8848
name: client
- containerPort: 9848
name: client-rpc
- containerPort: 9849
name: raft-rpc
- containerPort: 7848
name: old-raft-rpc
env:
- name: SPRING_DATASOURCE_PLATFORM
value: "mysql"
- name: MYSQL_SERVICE_HOST
valueFrom:
configMapKeyRef:
name: nacos-cm
key: mysql.host
- name: MYSQL_SERVICE_DB_NAME
valueFrom:
configMapKeyRef:
name: nacos-cm
key: mysql.db.name
- name: MYSQL_SERVICE_PORT
valueFrom:
configMapKeyRef:
name: nacos-cm
key: mysql.port
- name: MYSQL_SERVICE_USER
valueFrom:
configMapKeyRef:
name: nacos-cm
key: mysql.user
- name: MYSQL_SERVICE_PASSWORD
valueFrom:
configMapKeyRef:
name: nacos-cm
key: mysql.password
- name: MODE
value: "standalone"
- name: NACOS_SERVER_PORT
value: "8848"
- name: PREFER_HOST_MODE
value: "hostname"
selector:
matchLabels:
app: nacos-standalone
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-order.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-order
spec:
replicas: 1
selector:
matchLabels:
app: integrated-order
template:
metadata:
labels:
appName: integrated-order
app: integrated-order
spec:
containers:
- name: integrated-order
image: "{{ .Values.image.repository }}integrated-order"
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8013
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-praise-consumer.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-praise-consumer
spec:
replicas: 1
selector:
matchLabels:
app: integrated-praise-consumer
template:
metadata:
labels:
appName: integrated-praise-consumer
app: integrated-praise-consumer
spec:
containers:
- name: integrated-praise-consumer
image: "{{ .Values.image.repository }}integrated-praise-consumer"
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8014
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-praise-provider.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-praise-provider
spec:
replicas: 1
selector:
matchLabels:
app: integrated-praise-provider
template:
metadata:
labels:
appName: integrated-praise-provider
app: integrated-praise-provider
spec:
containers:
- name: integrated-praise-provider
image: "{{ .Values.image.repository }}integrated-praise-provider"
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8015
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-rocketmq.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: rocketmq
spec:
ports:
- port: 9876
protocol: TCP
targetPort: 9876
selector:
app: mqnamesrv
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mqnamesrv
spec:
serviceName: mqnamesrv
replicas: 1
selector:
matchLabels:
app: mqnamesrv
template:
metadata:
labels:
app: mqnamesrv
spec:
containers:
- name: mqnamesrv
image: registry.cn-hangzhou.aliyuncs.com/sca-community/rocketmq-server
command: ["sh","/usr/local/rocketmq-4.8.0/bin/mqnamesrv"]
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9876
protocol: TCP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mqbroker
spec:
serviceName: mqbroker
replicas: 1
selector:
matchLabels:
app: mqbroker
template:
metadata:
labels:
app: mqbroker
spec:
containers:
- name: mqbroker
image: registry.cn-hangzhou.aliyuncs.com/sca-community/rocketmq-server
command: ["sh","/usr/local/rocketmq-4.8.0/bin/mqbroker", "-n","rocketmq:9876"]
imagePullPolicy: IfNotPresent
env:
- name: JAVA_OPT
value: "-server -XX:ParallelGCThreads=1 -Xms1g -Xmx1g -Xmn512m"
ports:
- containerPort: 10909
- containerPort: 10911
resources:
requests:
memory: 128Mi
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-seata.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: seata-server
labels:
k8s-app: seata-server
spec:
type: ClusterIP
ports:
- port: 8091
name: server
selector:
k8s-app: seata-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: seata-server
labels:
k8s-app: seata-server
spec:
replicas: 1
selector:
matchLabels:
k8s-app: seata-server
template:
metadata:
labels:
k8s-app: seata-server
spec:
containers:
- name: seata-server
image: registry.cn-hangzhou.aliyuncs.com/sca-community/seata-server
imagePullPolicy: IfNotPresent
env:
- name: SEATA_PORT
value: '8091'
- name: STORE_MODE
value: file
ports:
- name: http
containerPort: 8091
protocol: TCP
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/templates/integrated-storage.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: integrated-storage
spec:
replicas: 1
selector:
matchLabels:
app: integrated-storage
template:
metadata:
labels:
appName: integrated-storage
app: integrated-storage
spec:
containers:
- name: integrated-storage
image: '{{ .Values.image.repository }}integrated-storage'
imagePullPolicy: Always
ports:
- name: http-port
containerPort: 8011
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/helm-chart/values.yaml
================================================
image:
repository: registry.cn-hangzhou.aliyuncs.com/sca-community/
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/Dockerfile
================================================
FROM openjdk:8-jdk-alpine as builder
LABEL author="yuluo" \
email="yuluo829@aliyun.com"
ADD ./integrated-account/target/integrated-account-*.jar /app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 8012
ENTRYPOINT ["java", "-jar","/app.jar"]
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0integrated-accountSpring Cloud Alibaba Integrated Account Exampleorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jcom.alibabadruid-spring-boot-starterorg.mybatis.spring.bootmybatis-spring-boot-startercom.alibaba.cloudspring-cloud-starter-alibaba-seatacom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configcom.alibaba.cloudintegrated-common${revision}org.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/src/main/java/com/alibaba/cloud/integration/account/AccountServiceApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author TrevorLink
*/
@SpringBootApplication
public class AccountServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AccountServiceApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/src/main/java/com/alibaba/cloud/integration/account/controller/AccountController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.controller;
import com.alibaba.cloud.integration.account.dto.AccountDTO;
import com.alibaba.cloud.integration.account.service.AccountService;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@PostMapping("/reduce-balance")
public Result> reduceBalance(@RequestBody AccountDTO accountDTO) {
try {
accountService.reduceBalance(accountDTO.getUserId(), accountDTO.getPrice());
}
catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return Result.success("");
}
@GetMapping("/")
public Result> getRemainAccount(String userId) {
return accountService.getRemainAccount(userId);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/src/main/java/com/alibaba/cloud/integration/account/dto/AccountDTO.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.dto;
/**
* @author TrevorLink
*/
public class AccountDTO {
private String userId;
private Integer price;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/src/main/java/com/alibaba/cloud/integration/account/mapper/AccountMapper.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.mapper;
import java.sql.Timestamp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface AccountMapper {
@Select("SELECT money FROM account WHERE user_id = #{userId}")
Integer getBalance(@Param("userId") String userId);
@Update("UPDATE account SET money = money - #{price},update_time = #{updateTime} WHERE user_id = #{userId} AND money >= ${price}")
int reduceBalance(@Param("userId") String userId, @Param("price") Integer price,
@Param("updateTime") Timestamp updateTime);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/src/main/java/com/alibaba/cloud/integration/account/service/AccountService.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.service;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
/**
* @author TrevorLink
*/
public interface AccountService {
void reduceBalance(String userId, Integer price) throws BusinessException;
Result> getRemainAccount(String userId);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/src/main/java/com/alibaba/cloud/integration/account/service/impl/AccountServiceImpl.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.account.mapper.AccountMapper;
import com.alibaba.cloud.integration.account.service.AccountService;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import org.apache.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author TrevorLink
*/
@Service
public class AccountServiceImpl implements AccountService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private AccountMapper accountMapper;
@Override
@Transactional
public void reduceBalance(String userId, Integer price) throws BusinessException {
logger.info("[reduceBalance] currenet XID: {}", RootContext.getXID());
checkBalance(userId, price);
Timestamp updateTime = new Timestamp(System.currentTimeMillis());
int updateCount = accountMapper.reduceBalance(userId, price, updateTime);
if (updateCount == 0) {
throw new BusinessException("reduce balance failed");
}
}
@Override
public Result> getRemainAccount(String userId) {
Integer balance = accountMapper.getBalance(userId);
if (balance == null) {
return Result.failed("wrong userId,please check the userId");
}
return Result.success(balance);
}
private void checkBalance(String userId, Integer price) throws BusinessException {
Integer balance = accountMapper.getBalance(userId);
if (balance < price) {
throw new BusinessException("no enough balance");
}
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-account/src/main/resources/application.yaml
================================================
server:
port: 8012
spring:
application:
name: integrated-account
cloud:
nacos:
discovery:
server-addr: nacos-server:8848
group: integrated-example
config:
server-addr: nacos-server:8848
group: integrated-example
file-extension: yaml
config:
import:
- optional:nacos:integrated-account.yaml
- optional:nacos:datasource-config.yaml
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
integrated-account-group: default
grouplist:
default: seata-server:8091
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-common/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0integrated-commonSpring Cloud Alibaba Integrated Common Example
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-common/src/main/java/com/alibaba/cloud/integration/common/BusinessException.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
/**
* @author TrevorLink
*/
public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-common/src/main/java/com/alibaba/cloud/integration/common/IResult.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
public interface IResult {
/**
* Get result code.
* @return result code
*/
Integer getCode();
/**
* Get result message.
* @return result message
*/
String getMessage();
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-common/src/main/java/com/alibaba/cloud/integration/common/Result.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
/**
* @author TrevorLink
*/
public class Result {
private Integer code;
private String message;
private T data;
public static Result success(T data) {
return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(),
data);
}
public static Result success(String message, T data) {
return new Result<>(ResultEnum.SUCCESS.getCode(), message, data);
}
public static Result> failed() {
return new Result<>(ResultEnum.COMMON_FAILED.getCode(),
ResultEnum.COMMON_FAILED.getMessage(), null);
}
public static Result> failed(String message) {
return new Result<>(ResultEnum.COMMON_FAILED.getCode(), message, null);
}
public static Result> failed(IResult errorResult) {
return new Result<>(errorResult.getCode(), errorResult.getMessage(), null);
}
public Result() {
}
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static Result instance(Integer code, String message, T data) {
Result result = new Result<>();
result.setCode(code);
result.setMessage(message);
result.setData(data);
return result;
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-common/src/main/java/com/alibaba/cloud/integration/common/ResultEnum.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
/**
* Integrated Example common result enum class.
* @author TrevorLink
*/
public enum ResultEnum implements IResult {
/**
* return success result.
*/
SUCCESS(2001, "接口调用成功"),
/**
* return business common failed.
*/
COMMON_FAILED(2003, "接口调用失败");
private Integer code;
private String message;
ResultEnum() {
}
ResultEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
@Override
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-frontend/Dockerfile
================================================
FROM openjdk:8-jdk-alpine as builder
LABEL author="yuluo" \
email="yuluo829@aliyun.com"
ADD ./integrated-frontend/target/integrated-frontend-*.jar /app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-frontend/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0jarintegrated-frontendSpring Cloud Alibaba Integrated Frontend Exampleorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-thymeleaforg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-frontend/src/main/java/com/alibaba/cloud/integration/frontend/FrontendApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.frontend;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author HuangSir
* @date 2022-09-08 14:11
*/
@SpringBootApplication
public class FrontendApplication {
public static void main(String[] args) {
SpringApplication.run(FrontendApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-frontend/src/main/java/com/alibaba/cloud/integration/frontend/controller/IntegrationController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.frontend.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author HuangSir
* @date 2022-09-08 14:00
*/
@Controller
public class IntegrationController {
@RequestMapping("/order")
public String order() {
return "order";
}
@RequestMapping("/rocketmq")
public String rocketmq() {
return "rocketmq";
}
@RequestMapping("/sentinel")
public String sentinel() {
return "sentinel";
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-frontend/src/main/resources/templates/order.html
================================================
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-gateway/Dockerfile
================================================
FROM openjdk:8-jdk-alpine as builder
LABEL author="yuluo" \
email="yuluo829@aliyun.com"
ADD ./integrated-gateway/target/integrated-gateway-*.jar /app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 30010
ENTRYPOINT ["java", "-jar","/app.jar"]
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-gateway/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0integrated-gatewaySpring Cloud Alibaba Integrated Gateway Exampleorg.springframework.cloudspring-cloud-starter-gateway-server-webfluxcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-netflix-ribboncom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.cloudspring-cloud-starter-loadbalancercom.alibaba.cspsentinel-spring-cloud-gateway-v6x-adapterorg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-gateway/src/main/java/com/alibaba/cloud/integration/gateway/GatewayApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author TrevorLink
*/
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-gateway/src/main/java/com/alibaba/cloud/integration/gateway/config/GatewayConfig.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.gateway.config;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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 jakarta.annotation.PostConstruct;
import reactor.core.publisher.Mono;
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.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
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;
/**
* @author TrevorLink
*/
@Configuration
public class GatewayConfig {
private final List viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfig(ObjectProvider> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
public void initGatewayRules() {
Set rules = new HashSet<>();
rules.add(
new GatewayFlowRule("praiseItemSentinel").setCount(5).setIntervalSec(1));
GatewayRuleManager.loadRules(rules);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers,
serverCodecConfigurer);
}
@PostConstruct
public void initBlockHandlers() {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono handleRequest(ServerWebExchange serverWebExchange,
Throwable throwable) {
return ServerResponse.status(HttpStatus.OK)
.contentType(new MediaType("application", "json", StandardCharsets.UTF_8))
.body(BodyInserters.fromValue("此接口被限流了"));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
@Bean
public CorsWebFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addAllowedOriginPattern("*");
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-gateway/src/main/resources/application.yaml
================================================
server:
port: 30010
spring:
application:
name: integrated-gateway
cloud:
nacos:
config:
server-addr: nacos-server:8848
group: integrated-example
file-extension: yaml
discovery:
server-addr: nacos-server:8848
group: integrated-example
config:
import: optional:nacos:integrated-gateway.yaml
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/Dockerfile
================================================
FROM openjdk:8-jdk-alpine as builder
LABEL author="yuluo" \
email="yuluo829@aliyun.com"
ADD ./integrated-order/target/integrated-order-*.jar /app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 8013
ENTRYPOINT ["java", "-jar","/app.jar"]
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0integrated-orderSpring Cloud Alibaba Integrated Order Exampleorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jcom.alibabadruid-spring-boot-starterorg.mybatis.spring.bootmybatis-spring-boot-startercom.alibaba.cloudspring-cloud-starter-alibaba-seatacom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-openfeigncom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.cloudspring-cloud-starter-loadbalancercom.alibaba.cloudintegrated-common${revision}org.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/OrderServiceApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author TrevorLink
*/
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/controller/OrderController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.controller;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
public Result> createOrder(@RequestParam("userId") String userId,
@RequestParam("commodityCode") String commodityCode,
@RequestParam("count") Integer count) {
Result> res = null;
try {
res = orderService.createOrder(userId, commodityCode, count);
}
catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return res;
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/entity/Order.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.entity;
import java.sql.Timestamp;
/**
* @author TrevorLink
*/
public class Order {
private Integer id;
private String userId;
private String commodityCode;
private Integer count;
private Integer money;
private Timestamp createTime;
private Timestamp updateTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getCommodityCode() {
return commodityCode;
}
public void setCommodityCode(String commodityCode) {
this.commodityCode = commodityCode;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
public Timestamp getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Timestamp updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ commodityCode + '\'' + ", count=" + count + ", money=" + money
+ ", createTime=" + createTime + ", updateTime=" + updateTime + '}';
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/feign/AccountServiceFeignClient.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.feign.dto.AccountDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* @author TrevorLink
*/
@FeignClient(name = "integrated-account")
public interface AccountServiceFeignClient {
@PostMapping("/account/reduce-balance")
Result> reduceBalance(@RequestBody AccountDTO accountReduceBalanceDTO);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/feign/StorageServiceFeignClient.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.feign.dto.StorageDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* @author TrevorLink
*/
@FeignClient(name = "integrated-storage")
public interface StorageServiceFeignClient {
@PostMapping("/storage/reduce-stock")
Result> reduceStock(@RequestBody StorageDTO productReduceStockDTO);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/feign/dto/AccountDTO.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign.dto;
/**
* @author TrevorLink
*/
public class AccountDTO {
private String userId;
private Integer price;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/feign/dto/StorageDTO.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign.dto;
/**
* @author TrevorLink
*/
public class StorageDTO {
private String commodityCode;
private Integer count;
public String getCommodityCode() {
return commodityCode;
}
public void setCommodityCode(String commodityCode) {
this.commodityCode = commodityCode;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/mapper/OrderMapper.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.mapper;
import com.alibaba.cloud.integration.order.entity.Order;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface OrderMapper {
@Insert("INSERT INTO `order` (user_id, commodity_code,money,create_time,update_time) VALUES (#{userId}, #{commodityCode},#{money},#{createTime},#{updateTime})")
@Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
int saveOrder(Order order);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/service/OrderService.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.service;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
/**
* @author TrevorLink
*/
public interface OrderService {
Result> createOrder(String userId, String commodityCode, Integer count)
throws BusinessException;
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/java/com/alibaba/cloud/integration/order/service/impl/OrderServiceImpl.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.entity.Order;
import com.alibaba.cloud.integration.order.feign.AccountServiceFeignClient;
import com.alibaba.cloud.integration.order.feign.StorageServiceFeignClient;
import com.alibaba.cloud.integration.order.feign.dto.AccountDTO;
import com.alibaba.cloud.integration.order.feign.dto.StorageDTO;
import com.alibaba.cloud.integration.order.mapper.OrderMapper;
import com.alibaba.cloud.integration.order.service.OrderService;
import org.apache.seata.core.context.RootContext;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import static com.alibaba.cloud.integration.common.ResultEnum.COMMON_FAILED;
/**
* @author TrevorLink
*/
@Service
public class OrderServiceImpl implements OrderService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private OrderMapper orderMapper;
@Autowired
private AccountServiceFeignClient accountService;
@Autowired
private StorageServiceFeignClient storageService;
@Override
@GlobalTransactional
public Result> createOrder(String userId, String commodityCode, Integer count) {
logger.info("[createOrder] current XID: {}", RootContext.getXID());
// deduct storage
StorageDTO storageDTO = new StorageDTO();
storageDTO.setCommodityCode(commodityCode);
storageDTO.setCount(count);
Integer storageCode = storageService.reduceStock(storageDTO).getCode();
if (storageCode.equals(COMMON_FAILED.getCode())) {
throw new BusinessException("stock not enough");
}
// deduct balance
int price = count * 2;
AccountDTO accountDTO = new AccountDTO();
accountDTO.setUserId(userId);
accountDTO.setPrice(price);
Integer accountCode = accountService.reduceBalance(accountDTO).getCode();
if (accountCode.equals(COMMON_FAILED.getCode())) {
throw new BusinessException("balance not enough");
}
// save order
Order order = new Order();
order.setUserId(userId);
order.setCommodityCode(commodityCode);
order.setCount(count);
order.setMoney(price);
order.setCreateTime(new Timestamp(System.currentTimeMillis()));
order.setUpdateTime(new Timestamp(System.currentTimeMillis()));
orderMapper.saveOrder(order);
logger.info("[createOrder] orderId: {}", order.getId());
return Result.success(order);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-order/src/main/resources/application.yaml
================================================
server:
port: 8013
spring:
application:
name: integrated-order
cloud:
nacos:
discovery:
server-addr: nacos-server:8848
group: integrated-example
config:
server-addr: nacos-server:8848
group: integrated-example
file-extension: yaml
config:
import:
- optional:nacos:integrated-order.yaml
- optional:nacos:datasource-config.yaml
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
integrated-order-group: default
grouplist:
default: seata-server:8091
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/Dockerfile
================================================
FROM openjdk:8-jdk-alpine as builder
LABEL author="yuluo" \
email="yuluo829@aliyun.com"
ADD ./integrated-praise-consumer/target/integrated-praise-consumer-*.jar /app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 8014
ENTRYPOINT ["java", "-jar","/app.jar"]
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0integrated-praise-consumerSpring Cloud Alibaba Integrated Praise Consumer Exampleorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jcom.alibabadruid-spring-boot-starterorg.mybatis.spring.bootmybatis-spring-boot-startercom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/java/com/alibaba/cloud/integration/consumer/PraiseConsumerApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author TrevorLink
*/
@SpringBootApplication
public class PraiseConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(PraiseConsumerApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/java/com/alibaba/cloud/integration/consumer/controller/PraiseController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.controller;
import com.alibaba.cloud.integration.consumer.service.PraiseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/praise")
public class PraiseController {
@Autowired
private PraiseService praiseService;
@GetMapping("/query")
public Integer getPraise(Integer itemId) {
return praiseService.getPraise(itemId);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/java/com/alibaba/cloud/integration/consumer/listener/ListenerAutoConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.listener;
import java.util.function.Consumer;
import com.alibaba.cloud.integration.consumer.message.PraiseMessage;
import com.alibaba.cloud.integration.consumer.service.PraiseService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
@Configuration
public class ListenerAutoConfiguration {
@Bean
public Consumer> consumer(PraiseService praiseService) {
return msg -> {
praiseService.praiseItem(msg.getPayload().getItemId());
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/java/com/alibaba/cloud/integration/consumer/mapper/PraiseMapper.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.mapper;
import java.sql.Timestamp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface PraiseMapper {
@Update("update item set praise = praise+1,update_time=#{updateTime} where id = #{itemId}")
int praiseItem(@Param("itemId") Integer itemId,
@Param("updateTime") Timestamp updateTime);
@Select("select praise from item where id = #{itemId}")
int getPraise(@Param("itemId") Integer itemId);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/java/com/alibaba/cloud/integration/consumer/message/PraiseMessage.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.message;
/**
* @author TrevorLink
*/
public class PraiseMessage {
private Integer itemId;
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
@Override
public String toString() {
return "PraiseMessage{" + "itemId=" + itemId + '}';
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/java/com/alibaba/cloud/integration/consumer/service/PraiseService.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.service;
/**
* @author TrevorLink
*/
public interface PraiseService {
void praiseItem(Integer itemId);
int getPraise(Integer itemId);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/java/com/alibaba/cloud/integration/consumer/service/impl/PraiseServiceImpl.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.consumer.mapper.PraiseMapper;
import com.alibaba.cloud.integration.consumer.service.PraiseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author TrevorLink
*/
@Service
public class PraiseServiceImpl implements PraiseService {
@Autowired
private PraiseMapper praiseMapper;
@Override
public void praiseItem(Integer itemId) {
Timestamp updateTime = new Timestamp(System.currentTimeMillis());
praiseMapper.praiseItem(itemId, updateTime);
}
@Override
public int getPraise(Integer itemId) {
return praiseMapper.getPraise(itemId);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-consumer/src/main/resources/application.yaml
================================================
spring:
application:
name: integrated-consumer
cloud:
nacos:
config:
file-extension: yaml
server-addr: nacos-server:8848
group: integrated-example
discovery:
server-addr: nacos-server:8848
group: integrated-example
config:
import:
- optional:nacos:integrated-consumer.yaml
- optional:nacos:datasource-config.yaml
server:
port: 8014
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-provider/Dockerfile
================================================
FROM openjdk:8-jdk-alpine as builder
LABEL author="yuluo" \
email="yuluo829@aliyun.com"
ADD ./integrated-praise-provider/target/integrated-praise-provider-*.jar /app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 8015
ENTRYPOINT ["java", "-jar","/app.jar"]
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-provider/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0integrated-praise-providerSpring Cloud Alibaba Integrated Praise Provider Exampleorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-stream-rocketmqcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-provider/src/main/java/com/alibaba/cloud/integration/provider/PraiseProviderApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author TrevorLink
*/
@SpringBootApplication
public class PraiseProviderApplication {
public static void main(String[] args) {
SpringApplication.run(PraiseProviderApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-provider/src/main/java/com/alibaba/cloud/integration/provider/controller/PraiseController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.provider.controller;
import com.alibaba.cloud.integration.provider.message.PraiseMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/praise")
public class PraiseController {
private static final String BINDING_NAME = "praise-output";
@Autowired
private StreamBridge streamBridge;
@GetMapping({ "/rocketmq", "/sentinel" })
public boolean praise(@RequestParam Integer itemId) {
PraiseMessage message = new PraiseMessage();
message.setItemId(itemId);
Message praiseMessage = MessageBuilder.withPayload(message)
.build();
return streamBridge.send(BINDING_NAME, praiseMessage);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-provider/src/main/java/com/alibaba/cloud/integration/provider/message/PraiseMessage.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.provider.message;
/**
* @author TrevorLink
*/
public class PraiseMessage {
private Integer itemId;
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
@Override
public String toString() {
return "PraiseMessage{" + "itemId=" + itemId + '}';
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-praise-provider/src/main/resources/application.yaml
================================================
spring:
application:
name: integrated-provider
cloud:
nacos:
config:
file-extension: yaml
server-addr: nacos-server:8848
group: integrated-example
discovery:
server-addr: nacos-server:8848
group: integrated-example
config:
import: optional:nacos:integrated-provider.yaml
server:
port: 8015
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/Dockerfile
================================================
FROM openjdk:8-jdk-alpine as builder
LABEL author="yuluo" \
email="yuluo829@aliyun.com"
ADD ./integrated-storage/target/integrated-storage-*.jar /app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 8011
ENTRYPOINT ["java", "-jar","/app.jar"]
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0integrated-storageSpring Cloud Alibaba Integrated Storage Exampleorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jcom.alibabadruid-spring-boot-starterorg.mybatis.spring.bootmybatis-spring-boot-startercom.alibaba.cloudspring-cloud-starter-alibaba-seatacom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configcom.alibaba.cloudintegrated-common${revision}org.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/src/main/java/com/alibaba/cloud/integration/storage/StorageServiceApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author TrevorLink
*/
@SpringBootApplication
public class StorageServiceApplication {
public static void main(String[] args) {
SpringApplication.run(StorageServiceApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/src/main/java/com/alibaba/cloud/integration/storage/controller/StorageController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.controller;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.storage.dto.StorageDTO;
import com.alibaba.cloud.integration.storage.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/storage")
public class StorageController {
@Autowired
private StorageService storageService;
@PostMapping("/reduce-stock")
public Result> reduceStock(@RequestBody StorageDTO storageDTO) {
try {
storageService.reduceStock(storageDTO.getCommodityCode(),
storageDTO.getCount());
}
catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return Result.success("");
}
@GetMapping("/")
public Result> getRemainCount(String commodityCode) {
return storageService.getRemainCount(commodityCode);
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/src/main/java/com/alibaba/cloud/integration/storage/dto/StorageDTO.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.dto;
/**
* @author TrevorLink
*/
public class StorageDTO {
private String commodityCode;
private Integer count;
public String getCommodityCode() {
return commodityCode;
}
public void setCommodityCode(String commodityCode) {
this.commodityCode = commodityCode;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/src/main/java/com/alibaba/cloud/integration/storage/mapper/StorageMapper.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.mapper;
import java.sql.Timestamp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface StorageMapper {
@Select("SELECT `count` FROM storage WHERE commodity_code = #{commodityCode}")
Integer getStock(@Param("commodityCode") String commodityCode);
@Update("UPDATE storage SET count = count - #{count},update_time=#{updateTime} WHERE commodity_code = #{commodityCode}")
int reduceStock(@Param("commodityCode") String commodityCode,
@Param("count") Integer count, @Param("updateTime") Timestamp updateTime);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/src/main/java/com/alibaba/cloud/integration/storage/service/StorageService.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.service;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
/**
* @author TrevorLink
*/
public interface StorageService {
void reduceStock(String commodityCode, Integer orderCount) throws BusinessException;
Result> getRemainCount(String commodityCode);
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/src/main/java/com/alibaba/cloud/integration/storage/service/impl/StorageServiceImpl.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.storage.mapper.StorageMapper;
import com.alibaba.cloud.integration.storage.service.StorageService;
import org.apache.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author TrevorLink
*/
@Service
public class StorageServiceImpl implements StorageService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private StorageMapper storageMapper;
@Override
@Transactional
public void reduceStock(String commodityCode, Integer count)
throws BusinessException {
logger.info("[reduceStock] current XID: {}", RootContext.getXID());
checkStock(commodityCode, count);
Timestamp updateTime = new Timestamp(System.currentTimeMillis());
int updateCount = storageMapper.reduceStock(commodityCode, count, updateTime);
if (updateCount == 0) {
throw new BusinessException("deduct stock failed");
}
}
@Override
public Result> getRemainCount(String commodityCode) {
Integer stock = storageMapper.getStock(commodityCode);
if (stock == null) {
return Result.failed("commodityCode wrong,please check commodity code");
}
return Result.success(stock);
}
private void checkStock(String commodityCode, Integer count)
throws BusinessException {
Integer stock = storageMapper.getStock(commodityCode);
if (stock < count) {
throw new BusinessException("no enough stock");
}
}
}
================================================
FILE: spring-cloud-alibaba-examples/integrated-example/integrated-storage/src/main/resources/application.yaml
================================================
server:
port: 8011
spring:
application:
name: integrated-storage
cloud:
nacos:
discovery:
server-addr: nacos-server:8848
group: integrated-example
config:
server-addr: nacos-server:8848
group: integrated-example
config:
import:
- optional:nacos:integrated-storage.yaml
- optional:nacos:datasource-config.yaml
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
integrated-storage-group: default
grouplist:
default: seata-server:8091
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0nacos-config-exampleSpring Cloud Starter Alibaba Nacos Config ExampleExample demonstrating how to use nacos configjarorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/com/alibaba/cloud/examples/NacosConfigApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author xiaojing, Jianwei Mao
*/
@SpringBootApplication
public class NacosConfigApplication {
public static void main(String[] args) {
SpringApplication.run(NacosConfigApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/com/alibaba/cloud/examples/example/BeanAutoRefreshConfigExample.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.example;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.cloud.examples.model.NacosConfigInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Dynamic bean refresh example.
*
* @author lixiaoshuang
*/
@RestController
@RequestMapping("/nacos/bean")
public class BeanAutoRefreshConfigExample {
@Autowired
private NacosConfigInfo nacosConfigInfo;
@GetMapping
public Map getConfigInfo() {
Map result = new HashMap<>();
result.put("serverAddr", nacosConfigInfo.getServerAddr());
result.put("prefix", nacosConfigInfo.getPrefix());
result.put("group", nacosConfigInfo.getGroup());
result.put("namespace", nacosConfigInfo.getNamespace());
return result;
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/com/alibaba/cloud/examples/example/ConfigListenerExample.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.example;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Configuration listener example.
*
* @author lixiaoshuang
*/
@Component
public class ConfigListenerExample {
Logger logger = LoggerFactory.getLogger(ConfigListenerExample.class);
/**
* Nacos dataId.
*/
public static final String DATA_ID = "nacos-config-example.properties";
/**
* Nacos group.
*/
public static final String GROUP = "DEFAULT_GROUP";
@Autowired
private NacosConfigManager nacosConfigManager;
@PostConstruct
public void init() throws NacosException {
ConfigService configService = nacosConfigManager.getConfigService();
configService.addListener(DATA_ID, GROUP, new Listener() {
@Override
public Executor getExecutor() {
return Executors.newSingleThreadExecutor();
}
@Override
public void receiveConfigInfo(String configInfo) {
logger.info("[dataId]:[" + DATA_ID + "],Configuration changed to:"
+ configInfo);
}
});
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/com/alibaba/cloud/examples/example/DockingInterfaceExample.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.example;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Example of docking with Nacos interface.
*
* @author lixiaoshuang
*/
@RestController
@RequestMapping("/nacos")
public class DockingInterfaceExample {
Logger logger = LoggerFactory.getLogger(DockingInterfaceExample.class);
/**
* Nacos group.
*/
public static final String DEFAULT_GROUP = "DEFAULT_GROUP";
@Autowired
private NacosConfigManager nacosConfigManager;
/**
* Get configuration information.
*
* @param dataId dataId
* @param group group
* @return config
*/
@RequestMapping("/getConfig")
public String getConfig(@RequestParam("dataId") String dataId,
@RequestParam(value = "group", required = false) String group)
throws NacosException {
if (StringUtils.isEmpty(group)) {
group = DEFAULT_GROUP;
}
ConfigService configService = nacosConfigManager.getConfigService();
return configService.getConfig(dataId, group, 2000);
}
/**
* Publish configuration.
*
* @param dataId dataId
* @param group group
* @param content content
* @return boolean
*/
@RequestMapping("/publishConfig")
public boolean publishConfig(@RequestParam("dataId") String dataId,
@RequestParam(value = "group", required = false) String group,
@RequestParam("content") String content) throws NacosException {
if (StringUtils.isEmpty(group)) {
group = DEFAULT_GROUP;
}
ConfigService configService = nacosConfigManager.getConfigService();
return configService.publishConfig(dataId, group, content);
}
/**
* Delete configuration.
*
* @param dataId dataId
* @param group group
* @return boolean
*/
@RequestMapping("/removeConfig")
public boolean removeConfig(@RequestParam("dataId") String dataId,
@RequestParam(value = "group", required = false) String group)
throws NacosException {
if (StringUtils.isEmpty(group)) {
group = DEFAULT_GROUP;
}
ConfigService configService = nacosConfigManager.getConfigService();
return configService.removeConfig(dataId, group);
}
/**
* Add listener configuration information.
*
* @param dataId dataId
* @param group group
*/
@RequestMapping("/listener")
public String listenerConfig(@RequestParam("dataId") String dataId,
@RequestParam(value = "group", required = false) String group)
throws NacosException {
if (StringUtils.isEmpty(group)) {
group = DEFAULT_GROUP;
}
ConfigService configService = nacosConfigManager.getConfigService();
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return Executors.newSingleThreadExecutor();
}
@Override
public void receiveConfigInfo(String configInfo) {
logger.info("[Listen for configuration changes]:{}", configInfo);
}
});
return "Add Lister successfully!";
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/com/alibaba/cloud/examples/example/ValueAnnotationExample.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.example;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Use the @Value annotation to get configuration example.
*
* @author lixiaoshuang
*/
@RestController
@RequestMapping("/nacos/annotation")
@RefreshScope
public class ValueAnnotationExample {
@Value("${spring.cloud.nacos.config.serverAddr:}")
private String serverAddr;
@Value("${spring.cloud.nacos.config.prefix:}")
private String prefix;
@Value("${spring.cloud.nacos.config.group:}")
private String group;
@Value("${spring.cloud.nacos.config.namespace:}")
private String namespace;
@GetMapping
public Map getConfigInfo() {
Map result = new HashMap<>(4);
result.put("serverAddr", serverAddr);
result.put("prefix", prefix);
result.put("group", group);
result.put("namespace", namespace);
return result;
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/com/alibaba/cloud/examples/model/NacosConfigInfo.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.model;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author lixiaoshuang
*/
@ConfigurationProperties(prefix = "spring.cloud.nacos.config")
@Component
public class NacosConfigInfo {
/**
* Nacos server address.
*/
private String serverAddr;
/**
* Data Id prefix.
*/
private String prefix;
/**
* Nacos group.
*/
private String group;
/**
* Nacos namespace.
*/
private String namespace;
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/resources/application.yaml
================================================
server:
port: 18084
spring:
application:
name: nacos-config-example
cloud:
nacos:
config:
serverAddr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
config:
import:
- nacos:nacos-config-example.properties?refreshEnabled=true
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: '*'
logging:
level:
com.alibaba.cloud.nacos.configdata: debug
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml
================================================
com.alibaba.cloudnacos-discovery-example${revision}4.0.0nacos-discovery-consumer-exampleSpring Cloud Starter Alibaba Nacos Discovery Consumer ExampleExample demonstrating how to use nacos discoveryjarorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-starter-actuatororg.springframework.cloudspring-cloud-starter-openfeignorg.springframework.cloudspring-cloud-starter-loadbalancerorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/error.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/test`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/feign-defaultmethod-error.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/divide-feign2?a=1`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/feign-error.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/divide-feign?a=1\&b=0`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/index.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/index`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/sleep.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/sleep`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/com/alibaba/cloud/examples/ConsumerApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author xiaojing, fangjian0423, MieAh
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@LoadBalancerClients({
@LoadBalancerClient("service-provider")
})
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/com/alibaba/cloud/examples/TestController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import com.alibaba.cloud.examples.feign.EchoClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* Example of remote invocation of service fusing and load balancing.
*
* @author xiaojing, fangjian0423, MieAh
*/
@RestController
public class TestController {
@Autowired
private RestTemplate urlCleanedRestTemplate;
@Autowired
private RestTemplate restTemplate;
@Autowired
private EchoClient echoClient;
@Autowired
private DiscoveryClient discoveryClient;
private static final String SERVICE_PROVIDER_ADDRESS = "http://service-provider";
@GetMapping("/echo-rest/{str}")
public String rest(@PathVariable String str) {
return urlCleanedRestTemplate
.getForObject(SERVICE_PROVIDER_ADDRESS + "/echo/" + str,
String.class);
}
@GetMapping("/index")
public String index() {
return restTemplate.getForObject(SERVICE_PROVIDER_ADDRESS, String.class);
}
@GetMapping("/test")
public String test() {
return restTemplate
.getForObject(SERVICE_PROVIDER_ADDRESS + "/test", String.class);
}
@GetMapping("/sleep")
public String sleep() {
return restTemplate
.getForObject(SERVICE_PROVIDER_ADDRESS + "/sleep", String.class);
}
@GetMapping("/notFound-feign")
public String notFound() {
return echoClient.notFound();
}
@GetMapping("/divide-feign")
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
return echoClient.divide(a, b);
}
@GetMapping("/divide-feign2")
public String divide(@RequestParam Integer a) {
return echoClient.divide(a);
}
@GetMapping("/echo-feign/{str}")
public String feign(@PathVariable String str) {
return echoClient.echo(str);
}
@GetMapping("/services/{service}")
public Object client(@PathVariable String service) {
return discoveryClient.getInstances(service);
}
@GetMapping("/services")
public Object services() {
return discoveryClient.getServices();
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/com/alibaba/cloud/examples/configuration/FeignConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import com.alibaba.cloud.examples.feign.EchoClient;
import com.alibaba.cloud.examples.feign.EchoClientFallback;
import org.springframework.context.annotation.Bean;
/**
* Configuration for Feign.
*
* @author fangjian0423, MieAh
*/
public class FeignConfiguration {
@Bean
public EchoClient echoClientFallback() {
return new EchoClientFallback();
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/com/alibaba/cloud/examples/configuration/RestTemplateConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* Load balancing and sentinel configuration for RestTemplate.
*
* @author fangjian0423, MieAh
*/
@Configuration
public class RestTemplateConfiguration {
@LoadBalanced
@Bean
// todo sentinel need to support GraalVM in future
// @SentinelRestTemplate(urlCleanerClass = UrlCleaner.class, urlCleaner = "clean")
public RestTemplate urlCleanedRestTemplate() {
return new RestTemplate();
}
@LoadBalanced
@Bean
// todo sentinel need to support GraalVM in future
// @SentinelRestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/com/alibaba/cloud/examples/configuration/UrlCleaner.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Change the request path containing echo.
*
* @author fangjian0423, MieAh
*/
public class UrlCleaner {
private static final Logger LOGGER = LoggerFactory.getLogger(UrlCleaner.class);
private static final String URL_CLEAN_ECHO = ".*/echo/.*";
public static String clean(String url) {
LOGGER.info("enter urlCleaner");
if (url.matches(URL_CLEAN_ECHO)) {
LOGGER.info("change url");
url = url.replaceAll("/echo/.*", "/echo/{str}");
}
return url;
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/com/alibaba/cloud/examples/feign/EchoClient.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Provide the external exposure interface of the service calling client.
*
* @author fangjian0423, MieAh
*/
@FeignClient(name = "service-provider", contextId = "service-provider")
public interface EchoClient {
/**
* Call the echo method of the remote provider or roll back when the service is blown.
*
* @param str str
* @return {@link String}
*/
@GetMapping("/echo/{str}")
String echo(@PathVariable("str") String str);
/**
* Call the divide method of the remote provider or roll back when the service is blown.
*
* @param a a
* @param b b
* @return {@link String}
*/
@GetMapping("/divide")
String divide(@RequestParam("a") Integer a, @RequestParam("b") Integer b);
/**
* Test that the default method calls the remote method is still a remote call.
*
* @param a a
* @return {@link String}
*/
default String divide(Integer a) {
return divide(a, 0);
}
/**
* Call the notFound method of the remote provider or roll back when the service is blown.
*
* @return {@link String}
*/
@GetMapping("/notFound")
String notFound();
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/com/alibaba/cloud/examples/feign/EchoClientFallback.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
/**
* When the service is blown, the fallback operation is performed.
*
* @author fangjian0423, MieAh
*/
public class EchoClientFallback implements EchoClient {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
@Override
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
return "divide fallback";
}
@Override
public String notFound() {
return "notFound fallback";
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties
================================================
spring.application.name=service-consumer
server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.fail-fast=true
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
feign.sentinel.enabled=true
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds2.file.data-type=json
spring.cloud.sentinel.datasource.ds2.file.rule-type=degrade
spring.cloud.loadbalancer.nacos.enabled=true
# use feign client in GraalVM environment need to set below config
spring.cloud.refresh.enabled=false
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/degraderule.json
================================================
[
{
"resource": "GET:http://service-provider/test",
"count": 0.5,
"grade": 1,
"timeWindow": 30
},
{
"resource": "GET:http://service-provider",
"count": 0.5,
"grade": 1,
"timeWindow": 10
},
{
"resource": "GET:http://service-provider/sleep",
"count": 20.0,
"grade": 0,
"timeWindow": 30
},
{
"resource": "GET:http://service-provider/divide",
"count": 0.5,
"grade": 1,
"timeWindow": 30
}
]
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/flowrule.json
================================================
[
{
"resource": "GET:http://service-provider/echo/{str}",
"controlBehavior": 0,
"count": 1,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/pom.xml
================================================
com.alibaba.cloudnacos-discovery-example${revision}4.0.0nacos-discovery-consumer-sclb-exampleSpring Cloud Starter Alibaba Nacos Discovery x Load Balancer ExampleExample demonstrating how to use nacos discoveryjarorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-netflix-ribbonorg.springframework.bootspring-boot-starter-actuatororg.springframework.cloudspring-cloud-starter-loadbalancercom.alibaba.cloudspring-cloud-starter-alibaba-sentinelorg.springframework.cloudspring-cloud-commonsorg.springframework.cloudspring-cloud-starter-openfeignorg.springframework.cloudspring-cloud-starter-netflix-ribbonorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/scripts/error.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/test`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/scripts/feign-defaultmethod-error.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/divide-feign2?a=1`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/scripts/feign-error.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/divide-feign?a=1\&b=0`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/scripts/index.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/index`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/scripts/resttemplate.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/echo-rest/resttemplate`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/scripts/sleep.sh
================================================
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/sleep`
let n++
done
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/ConsumerSCLBApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
*
* @author fangjian0423, MieAh
*/
@SpringBootApplication
@EnableDiscoveryClient(autoRegister = false)
@EnableFeignClients
public class ConsumerSCLBApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerSCLBApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/RandomLoadBalancer.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.List;
import java.util.Random;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
/**
* Self-defined randomLoadBalancer.
*
* @author fangjian0423, MieAh
*/
public class RandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private ObjectProvider serviceInstanceListSupplierProvider;
private final String serviceId;
private final Random random;
public RandomLoadBalancer(
ObjectProvider serviceInstanceListSupplierProvider,
String serviceId) {
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
this.serviceId = serviceId;
this.random = new Random();
}
@Override
public Mono> choose(
org.springframework.cloud.client.loadbalancer.Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
@Override
public Mono> choose() {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
private Response getInstanceResponse(
List instances) {
if (instances.isEmpty()) {
return new EmptyResponse();
}
ServiceInstance instance = instances.get(random.nextInt(instances.size()));
return new DefaultResponse(instance);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/TestController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import com.alibaba.cloud.examples.feign.EchoClient;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* Example of remote invocation of service fusing and custom load balancing.
*
* @author fangjian0423, MieAh
*/
@RestController
public class TestController {
@Resource
private RestTemplate urlCleanedRestTemplate;
@Resource
private RestTemplate restTemplate;
@Resource
private EchoClient echoClient;
@Resource
private DiscoveryClient discoveryClient;
@Value("${spring.cloud.loadbalancer.zone:null}")
private String zone;
private static final String SERVICE_PROVIDER_ADDRESS = "http://service-provider";
@GetMapping("/echo-rest/{str}")
public String rest(@PathVariable String str) {
return urlCleanedRestTemplate
.getForObject(SERVICE_PROVIDER_ADDRESS + "/echo/" + str,
String.class);
}
@GetMapping("/zone")
public String zone() {
return "consumer zone " + zone + "\n" + urlCleanedRestTemplate
.getForObject(SERVICE_PROVIDER_ADDRESS + "/zone", String.class);
}
@GetMapping("/echo-feign/{str}")
public String feign(@PathVariable String str) {
return echoClient.echo(str);
}
@GetMapping("/index")
public String index() {
return restTemplate.getForObject(SERVICE_PROVIDER_ADDRESS, String.class);
}
@GetMapping("/test")
public String test() {
return restTemplate.getForObject(SERVICE_PROVIDER_ADDRESS + "/test",
String.class);
}
@GetMapping("/sleep")
public String sleep() {
return restTemplate.getForObject(SERVICE_PROVIDER_ADDRESS + "/sleep",
String.class);
}
@GetMapping("/notFound-feign")
public String notFound() {
return echoClient.notFound();
}
@GetMapping("/divide-feign")
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
return echoClient.divide(a, b);
}
@GetMapping("/divide-feign2")
public String divide(@RequestParam Integer a) {
return echoClient.divide(a);
}
@GetMapping("/services/{service}")
public Object client(@PathVariable String service) {
return discoveryClient.getInstances(service);
}
@GetMapping("/services")
public Object services() {
return discoveryClient.getServices();
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/config/FeignConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.config;
import com.alibaba.cloud.examples.feign.EchoClient;
import com.alibaba.cloud.examples.feign.EchoClientFallback;
import org.springframework.context.annotation.Bean;
/**
* Configuration for Feign.
*
* @author fangjian0423, MieAh
*/
public class FeignConfiguration {
@Bean
public EchoClient echoClientFallback() {
return new EchoClientFallback();
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/config/MyLoadBalancerConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.config;
import com.alibaba.cloud.examples.RandomLoadBalancer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
/**
* Configure for load balancing.
*
* @author fangjian0423, MieAh
*/
public class MyLoadBalancerConfiguration {
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,
ServiceInstanceListSupplier.class), name);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/config/MySCLBConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.config;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Configuration;
/**
* Configuration for Self-defined randomLoadBalancer.
*
* @author fangjian0423, MieAh
*/
@Configuration
@LoadBalancerClient(value = "service-provider", configuration = MyLoadBalancerConfiguration.class)
public class MySCLBConfiguration {
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/config/RestTemplateConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.config;
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* Load balancing and sentinel configuration for RestTemplate.
*
* @author fangjian0423, MieAh
*/
@Configuration
public class RestTemplateConfiguration {
@LoadBalanced
@Bean
@SentinelRestTemplate(urlCleanerClass = UrlCleaner.class, urlCleaner = "clean")
public RestTemplate urlCleanedRestTemplate() {
return new RestTemplate();
}
@LoadBalanced
@Bean
@SentinelRestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/config/UrlCleaner.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Change the request path containing echo.
*
* @author fangjian0423, MieAh
*/
public class UrlCleaner {
private static final Logger LOGGER = LoggerFactory.getLogger(UrlCleaner.class);
private static final String URL_CLEAN_ECHO = ".*/echo/.*";
public static String clean(String url) {
LOGGER.info("enter urlCleaner");
if (url.matches(URL_CLEAN_ECHO)) {
LOGGER.info("change url");
url = url.replaceAll("/echo/.*", "/echo/{str}");
}
return url;
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/feign/EchoClient.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import com.alibaba.cloud.examples.config.FeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Provide the external exposure interface of the service calling client.
*
* @author fangjian0423, MieAh
*/
@FeignClient(name = "service-provider", fallback = EchoClientFallback.class, configuration = FeignConfiguration.class)
public interface EchoClient {
/**
* Call the echo method of the remote provider or roll back when the service is blown.
*
* @param str str
* @return {@link String}
*/
@GetMapping("/echo/{str}")
String echo(@PathVariable("str") String str);
/**
* Call the divide method of the remote provider or roll back when the service is blown.
*
* @param a a
* @param b b
* @return {@link String}
*/
@GetMapping("/divide")
String divide(@RequestParam("a") Integer a, @RequestParam("b") Integer b);
/**
* Test that the default method calls the remote method is still a remote call.
*
* @param a a
* @return {@link String}
*/
default String divide(Integer a) {
return divide(a, 0);
}
/**
* Call the notFound method of the remote provider or roll back when the service is blown.
*
* @return {@link String}
*/
@GetMapping("/notFound")
String notFound();
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/java/com/alibaba/cloud/examples/feign/EchoClientFallback.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
/**
* When the service is blown, the fallback operation is performed.
*
* @author fangjian0423, MieAh
*/
public class EchoClientFallback implements EchoClient {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
@Override
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
return "divide fallback";
}
@Override
public String notFound() {
return "notFound fallback";
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/resources/application.properties
================================================
spring.application.name=service-consumer-sclb
server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.configurations=zone-preference
spring.cloud.loadbalancer.zone=hangzhou
feign.sentinel.enabled=true
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds2.file.data-type=json
spring.cloud.sentinel.datasource.ds2.file.rule-type=degrade
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/resources/degraderule.json
================================================
[
{
"resource": "GET:http://service-provider/test",
"count": 0.5,
"grade": 1,
"timeWindow": 30
},
{
"resource": "GET:http://service-provider",
"count": 0.5,
"grade": 1,
"timeWindow": 10
},
{
"resource": "GET:http://service-provider/sleep",
"count": 20.0,
"grade": 0,
"timeWindow": 30
},
{
"resource": "GET:http://service-provider/divide",
"count": 0.5,
"grade": 1,
"timeWindow": 30
}
]
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-sclb-example/src/main/resources/flowrule.json
================================================
[
{
"resource": "GET:http://service-provider/echo/{str}",
"controlBehavior": 0,
"count": 2,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/pom.xml
================================================
com.alibaba.cloudnacos-discovery-example${revision}4.0.0nacos-discovery-provider-exampleSpring Cloud Starter Alibaba Nacos Discovery Provider ExampleExample demonstrating how to use nacos discoveryjarorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/com/alibaba/cloud/examples/EchoController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.Map;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import jakarta.annotation.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Provide interfaces to consumers.
*
* @author fangjian0423, MieAh
*/
@RestController
public class EchoController {
@Resource
private NacosDiscoveryProperties nacosDiscoveryProperties;
@GetMapping("/")
public ResponseEntity index() {
return new ResponseEntity<>("index error", HttpStatus.INTERNAL_SERVER_ERROR);
}
@GetMapping("/test")
public ResponseEntity test() {
return new ResponseEntity<>("error", HttpStatus.INTERNAL_SERVER_ERROR);
}
@GetMapping("/sleep")
public String sleep() {
try {
Thread.sleep(1000L);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return "ok";
}
@GetMapping("/echo/{string}")
public String echo(@PathVariable String string) {
return "hello Nacos Discovery " + string;
}
@GetMapping("/divide")
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
if (b == 0) {
return String.valueOf(0);
}
else {
return String.valueOf(a / b);
}
}
@GetMapping("/zone")
public String zone() {
Map metadata = nacosDiscoveryProperties.getMetadata();
return "provider zone " + metadata.get("zone");
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/com/alibaba/cloud/examples/ProviderApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author xiaojing, fangjian0423, MieAh
*/
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties
================================================
server.port=0
spring.application.name=service-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true
#spring.cloud.nacos.discovery.instance-enabled=true
#only register IPv4 instance
#spring.cloud.nacos.discovery.ip-type=IPv4
#only register IPv6 instance
#spring.cloud.nacos.discovery.ip-type=IPv6
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-spring-cloud-config-client-example/pom.xml
================================================
com.alibaba.cloudnacos-discovery-example${revision}4.0.0nacos-discovery-spring-cloud-config-client-exampleSpring Cloud Starter Alibaba Nacos Discovery x Config Client ExampleExample demonstrating how to use nacos discoveryjarorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-configorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-spring-cloud-config-client-example/src/main/java/com/alibaba/cloud/examples/GetConfigController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Provide the interface method of config.
*
* @author MieAh
*/
@RestController
public class GetConfigController {
@Value("${config}")
private String config;
@GetMapping("/config")
public String getConfig() {
return config;
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-spring-cloud-config-client-example/src/main/java/com/alibaba/cloud/examples/SpringCloudConfigClientApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author JevonYang
*/
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConfigClientApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-spring-cloud-config-client-example/src/main/resources/application.yml
================================================
server:
port: 18083
spring:
application:
name: client
config:
import: optional:configserver:http://localhost:7070
cloud:
nacos:
username: nacos
password: nacos
discovery:
server-addr: 127.0.0.1:8848
config: config-from-yml
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-spring-cloud-config-server-example/pom.xml
================================================
com.alibaba.cloudnacos-discovery-example${revision}4.0.0nacos-discovery-spring-cloud-config-server-exampleSpring Cloud Starter Alibaba Nacos Discovery x Config Server ExampleExample demonstrating how to use nacos discoveryjarorg.springframework.bootspring-boot-starter-weborg.springframework.cloudspring-cloud-config-servercom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-starter-testtestorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-spring-cloud-config-server-example/src/main/java/com/alibaba/cloud/examples/SpringCloudConfigServerApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;
/**
* @author Jim
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
public class SpringCloudConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConfigServerApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-spring-cloud-config-server-example/src/main/resources/application.yml
================================================
server:
port: 7070
spring:
application:
name: configserver
cloud:
nacos:
username: 'nacos'
password: 'nacos'
discovery:
server-addr: 127.0.0.1:8848
config:
server:
git:
uri: https://github.com/fangjian0423/blogimages
search-paths: /
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-reactivediscovery-consumer-example/pom.xml
================================================
com.alibaba.cloudnacos-discovery-example${revision}4.0.0nacos-reactivediscovery-consumer-exampleSpring Cloud Starter Alibaba Nacos Discovery Reactive ExampleExample demonstrating how to use nacos discoveryjarorg.springframework.bootspring-boot-starter-webfluxcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-netflix-ribbonorg.springframework.bootspring-boot-starter-actuatororg.springframework.cloudspring-cloud-starter-loadbalancerorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-reactivediscovery-consumer-example/src/main/java/com/alibaba/cloud/examples/ConsumerReactiveApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
/**
* @author Jim
*/
@SpringBootApplication
@LoadBalancerClients({
@LoadBalancerClient("service-provider")
})
public class ConsumerReactiveApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerReactiveApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-reactivediscovery-consumer-example/src/main/java/com/alibaba/cloud/examples/MyController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import jakarta.annotation.Resource;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Example of responsive discovery client.
*
* @author fangjian0423, MieAh
*/
@RestController
public class MyController {
@Resource
private ReactiveDiscoveryClient reactiveDiscoveryClient;
@Resource
private WebClient.Builder webClientBuilder;
@GetMapping("/all-services")
public Flux allServices() {
return reactiveDiscoveryClient.getInstances("service-provider")
.map(serviceInstance -> serviceInstance.getHost() + ":"
+ serviceInstance.getPort());
}
@GetMapping("/service-call/{name}")
public Mono serviceCall(@PathVariable("name") String name) {
return webClientBuilder.build().get()
.uri("http://service-provider/echo/" + name).retrieve()
.bodyToMono(String.class);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-reactivediscovery-consumer-example/src/main/java/com/alibaba/cloud/examples/WebClientConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Configuration for web client.
*
* @author fangjian0423, MieAh
*/
@Configuration
public class WebClientConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder webClient() {
return WebClient.builder();
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-reactivediscovery-consumer-example/src/main/resources/application.properties
================================================
spring.application.name=service-consumer-reactive
server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
spring.cloud.loadbalancer.ribbon.enabled=false
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0nacos-discovery-exampleSpring Cloud Starter Alibaba Nacos Discovery ExamplesExample demonstrating how to use nacos discoverypomnacos-discovery-consumer-examplenacos-discovery-consumer-sclb-examplenacos-reactivediscovery-consumer-examplenacos-discovery-provider-examplenacos-discovery-spring-cloud-config-server-examplenacos-discovery-spring-cloud-config-client-example
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/pom.xml
================================================
com.alibaba.cloudnacos-gateway-example${revision}4.0.0nacos-gateway-discovery-exampleSpring Cloud Starter Alibaba Nacos Discovery x Gateway ExampleExample demonstrating how to use gateway with nacosjarorg.springframework.cloudspring-cloud-starter-gateway-server-webfluxcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-starter-actuatororg.springframework.cloudspring-cloud-starter-loadbalancerorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/java/com/alibaba/cloud/examples/GatewayApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
/**
* @author lengleng
*/
@SpringBootApplication
@EnableDiscoveryClient
@LoadBalancerClients({
@LoadBalancerClient("service-gateway-provider")
})
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/resources/application.properties
================================================
server.port=18085
spring.application.name=service-gateway
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
management.endpoints.web.exposure.include=*
# spring cloud route config
spring.cloud.gateway.server.webflux.routes[0].id=nacos-route
spring.cloud.gateway.server.webflux.routes[0].uri=lb://service-gateway-provider
spring.cloud.gateway.server.webflux.routes[0].predicates[0].name=Path
spring.cloud.gateway.server.webflux.routes[0].predicates[0].args[pattern]=/nacos/**
spring.cloud.gateway.server.webflux.routes[0].filters[0]=StripPrefix=1
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/pom.xml
================================================
com.alibaba.cloudnacos-gateway-example${revision}4.0.0nacos-gateway-provider-exampleSpring Cloud Starter Alibaba Nacos Discovery x Gateway - Provider ExampleExample demonstrating how to use gateway with nacosjarorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/java/com/alibaba/cloud/examples/EchoController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Provide a service interface to the gateway for forwarding calls.
*
* @author MieAh
*/
@RestController
public class EchoController {
@GetMapping("/echo/{string}")
public String echo(@PathVariable String string) {
return "hello Nacos Discovery " + string;
}
@GetMapping("/divide")
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
return String.valueOf(a / b);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/java/com/alibaba/cloud/examples/ProviderApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author xiaojing
*/
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/resources/application.properties
================================================
server.port=18086
spring.application.name=service-gateway-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
management.endpoints.web.exposure.include=*
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0nacos-gateway-exampleSpring Cloud Starter Alibaba Nacos Discovery x Gateway ExamplesExample demonstrating how to use gateway with nacospomnacos-gateway-discovery-examplenacos-gateway-provider-example
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/readme-zh.md
================================================
# Spring Cloud Alibaba Nacos Example
## 项目说明
本项目演示如何使用 Spring Cloud Alibaba Nacos 相关 Starter 完成 Spring Cloud 应用的服务发现和配置管理。
[Nacos](https://github.com/alibaba/Nacos) 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
## 正确配置并启动 Nacos Server 3.1.0
在 Nacos 3.1.0 中,加入了用户鉴权相关的功能,在首次启动 Nacos Server 时,需要正确配置,避免出现启动失败的问题。
### 下载 Nacos Server
> 本示例中使用 Nacos Server 版本为 3.1.0!
Nacos 支持直接下载和源码构建两种方式。**推荐在 Spring Cloud Alibaba 2023.x 中使用 Nacos Server 3.1.0 版本。**
1. 直接下载:[Nacos Server 下载页](https://github.com/alibaba/nacos/releases)
2. 源码构建:进入 Nacos [Github 项目页面](https://github.com/alibaba/nacos),将代码 git clone 到本地自行编译打包,[参考文档](https://nacos.io/zh-cn/docs/quick-start.html)。
### 配置 Nacos Server
打开 `\nacos-server-3.1.0\conf\application.properties` 配置文件,修改以下配置项:
#### 配置数据源
此处以 MySQL 数据库为例,使用 `nacos-server-3.1.0\conf\mysql-schema.sql` 初始化数据库表文件。同时修改以下配置
```properties
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
db.user.0=root
db.password.0=root
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
```
#### 开启鉴权
**注意:不开启在 3.1.0 中会出现登陆失败异常!**
```properties
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=true
```
#### 设置服务端验证 key
```properties
nacos.core.auth.server.identity.key=test
nacos.core.auth.server.identity.value=test
```
#### 设置默认 token
```properties
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
```
**在使用 Nacos 服务发现和配置功能时,一定要配置 `username` 和 `password` 属性,否则会出现用户未找到异常!**
#### Open API 鉴权
在 nacos server 3.1.0 中使用 Open api 接口时需要鉴权:更多细节请参考:[Nacos api 鉴权](https://nacos.io/zh-cn/docs/auth.html)
1. 获取 accessToken:使用用户名和密码登陆 nacos server:
`curl -X POST '127.0.0.1:8848/nacos/v1/auth/login' -d 'username=nacos&password=nacos'`
若用户名和密码正确,返回信息如下:
`{"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYwNTYyOTE2Nn0.2TogGhhr11_vLEjqKko1HJHUJEmsPuCxkur-CfNojDo","tokenTtl":18000,"globalAdmin":true}`
2. 使用 accessToken 请求 nacos api 接口:
`curl -X GET '127.0.0.1:8848/nacos/v1/cs/configs?accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYwNTYyMzkyM30.O-s2yWfDSUZ7Svd3Vs7jy9tsfDNHs1SuebJB4KlNY8Q&dataId=nacos.example.1&group=nacos_group'`
### 启动 Nacos Server
1. 启动 Nacos Server,进入下载到本地并解压完成后的文件夹(使用源码构建的方式则进入编译打包好的文件夹),再进去其相对文件夹 `nacos/bin`,并对照操作系统实际情况执行如下命令。[详情参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。
1. Linux/Unix/Mac 操作系统,执行命令
`sh startup.sh -m standalone`
2. Windows 操作系统,执行命令
`cmd startup.cmd`
2. 访问 Nacos Server Console
浏览器输入地址 http://127.0.0.1:8848/nacos ,**首次登陆需要绑定 nacos 用户,因为新版本增加了鉴权,需要应用注册和配置绑定时配置用户名和密码。**
## Nacos 应用示例
### Spring Cloud Alibaba Nacos Config
#### 配置方式更新说明
在2023.0.1.3版本中,为了支持在SpringBoot中接入Nacos配置中心以及基于原有的nacos config模块之上支持@NacosConfig,@NacosConfigListener注解,将spring-cloud-starter-alibaba-nacos-config模块进行了拆分
- **spring-alibaba-nacos-config**:仅依赖SpringBoot,支持在非SpringCloud应用中独立使用
- **spring-cloud-starter-alibaba-nacos-config**:仅保留依赖SpringCloud的组件
在模块拆分的过程中,发现随着代码不断的变更,配置的加载逻辑存在多个分支,包括最初版本中通过拼接spring.application.name以及fileExtension等参数,通过share-configs,extension-configs以及spring.config.import。多个属性源加载时机不一致且代码逻辑分叉,**不利于配置模块的扩展**。
出于代码的可维护性考虑,对配置加载逻辑进行了删减,仅保留了spring在Spring Boot 2.4.0 (2020年11月12日)推出的**spring.config.import标准配置导入方式**,在该版本中Spring同时建议**废弃bootstrap模式**启动,统一迁移到**application.properties**。
对于之前通过application.name拼接模式以及share-configs,extension-configs等方式导入的配置,需要**统一修改**为**spring.config.import**模式进行配置导入。
**接入NacosConfig的标准用法如下**
- 导入单个配置
```
spring:
config:
import:nacos:application.propertise?refreshEnabled=true&group=DEFAULT_GROUP
cloud:
nacos:
config:
serverAddr: {nacos server addr}
namespace: {nacos namespace id}
```
- 导入多个配置
```
spring:
config:
import:
- nacos:application.propertise?group=refreshEnabled=true&group=DEFAULT_GROUP
- nacos:{other config data id}?group={other config group}&refreshEnabled=true
cloud:
nacos:
config:
serverAddr: {nacos server addr}
namespace: {nacos namespace id}
```
#### 应用接入
在启动应用示例进行项目功能演示之前,先了解一下 Spring Cloud 应用如何接入 Nacos Config 作为服务配置中心。
**注意 本章节只是为了便于理解接入方式,本示例代码中已经完成接入工作,无需再进行修改。**
1. 首先,修改 `pom.xml` 文件,引入 spring-cloud-starter-alibaba-nacos-config ;
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-nacos-config
```
2. 在应用的 `/src/main/resources/application.yaml` 配置文件中配置 Nacos 地址并引入服务配置;
```yml
spring:
cloud:
nacos:
serverAddr: 127.0.0.1:8848
# 以下配置项必须填写
username: 'nacos'
password: 'nacos'
config:
import:
- nacos:nacos-config-example.properties?refreshEnabled=true&group=DEFAULT_GROUP
```
3. 完成上述两步后,应用会从 Nacos Server 中获取相应的配置,并添加在 Spring Environment 的 PropertySources 中。使用 Nacos 配置中心保存 Nacos 的部分配置时,有以下四种方式:
- BeanAutoRefreshConfigExample: 通过将配置信息配置为bean,支持配置变自动刷新的例子;
- ConfigListenerExample: 监听配置信息的例子;
- DockingInterfaceExample: 对接 Nacos 接口,通过接口完成对配置信息增删改查的例子;
- ValueAnnotationExample: 通过 @Value 注解进行配置信息获取的例子。
#### Nacos Server 中添加配置
在命令行执行如下命令,向 Nacos Server 中添加一条配置。**可直接通过 Nacos 控制台注入!**
> **注意:需要替换 accessToken。**
```shell
$ curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?accessToken=XXXXXXXXXXXXXXXXXXXXXXXX&dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=spring.cloud.nacos.config.serverAddr=127.0.0.1:8848%0Aspring.cloud.nacos.config.prefix=PREFIX%0Aspring.cloud.nacos.config.group=GROUP%0Aspring.cloud.nacos.config.namespace=NAMESPACE"
```
添加的配置详情如下:
```properties
# dataId 为 nacos-config-example.properties
# group 为 DEFAULT_GROUP
# 内容如下:
spring.cloud.nacos.config.serveraddr=127.0.0.1:8848
spring.cloud.nacos.config.prefix=PREFIX
spring.cloud.nacos.config.group=GROUP
spring.cloud.nacos.config.namespace=NAMESPACE
```
#### 应用启动
1. 增加配置,在应用的 `/src/main/resources/application.yml` 中添加基本配置信息;
```yml
server:
port: 18084
management:
endpoints:
web:
exposure:
include: '*'
```
2. 启动应用,支持 IDE 直接启动和编译打包后启动。
1. IDE直接启动:找到主类 `NacosConfigApplication`,执行 main 方法启动应用。
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,进入 `target` 文件夹执行 `java -jar nacos-config-example.jar` 启动应用。
#### 验证
##### 验证自动注入
在浏览器地址栏输入 `http://127.0.0.1:18084/nacos/bean`,并点击调转,可以看到成功从 Nacos Server 中获取了数据。

##### 验证动态刷新
1. 执行如下命令,修改 Nacos Server 端的配置数据
```shell
$ curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?accessToken=XXXXXXXXXXXXXXXXXXXXXXXXXXX&dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=spring.cloud.nacos.config.serveraddr=127.0.0.1:8848%0Aspring.cloud.nacos.config.prefix=PREFIX%0Aspring.cloud.nacos.config.group=DEFAULT_GROUP%0Aspring.cloud.nacos.config.namespace=NAMESPACE"
```
2. 在浏览器地址栏输入 `http://127.0.0.1:18084/nacos/bean`,并点击调转,可以看到应用从 Nacos Server 中获取了最新的数据,group 变成了 DEFAULT_GROUP。

#### 原理
##### Nacos Config 数据结构
Nacos Config 主要通过 dataId 和 group 来唯一确定一条配置,假定您已经了解此背景。如果不了解,请参考 [Nacos 文档](https://nacos.io/zh-cn/docs/concepts.html)。
Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 `ConfigService.getConfig(String dataId, String group, long timeoutMs)`。
##### Spring Cloud 应用获取数据
###### dataID
在 Nacos Config Starter 中,dataId 的拼接格式如下
${prefix} - ${spring.profiles.active} . ${file-extension}
* `prefix` 默认为 `spring.application.name` 的值,也可以通过配置项 `spring.cloud.nacos.config.prefix`来配置。
* `spring.profiles.active` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
**注意,当 active profile 为空时,对应的连接符 `-` 也将不存在,dataId 的拼接格式变成 `${prefix}`.`${file-extension}`**
* `file-extension` 为配置内容的数据格式,可以通过配置项 `spring.cloud.nacos.config.file-extension`来配置。
目前只支持 `properties` 类型。
###### group
* `group` 默认为 `DEFAULT_GROUP`,可以通过 `spring.cloud.nacos.config.group` 配置。
##### 自动注入
Spring Cloud Alibaba Nacos Config Starter 实现了 `org.springframework.boot.context.config.ConfigDataLoader` 接口,并将优先级设置成了最高。
在 Spring Cloud 应用启动阶段,会主动从 Nacos Server 端获取对应的数据,并将获取到的数据转换成 PropertySource 且注入到 Environment 的 PropertySources 属性中,所以使用 @Value 注解也能直接获取 Nacos Server 端配置的内容。
##### 动态刷新
Nacos Config Starter 默认为所有获取数据成功的 Nacos 的配置项添加了监听功能,在监听到服务端配置发生变化时会实时触发 `org.springframework.cloud.context.refresh.ContextRefresher` 的 refresh 方法 。
如果需要对 Bean 进行动态刷新,请参照 Spring 和 Spring Cloud 规范。推荐给类添加 `@RefreshScope` 或 `@ConfigurationProperties ` 注解,
更多详情请参考 [ContextRefresher Java Doc](http://static.javadoc.io/org.springframework.cloud/spring-cloud-context/2.0.0.RELEASE/org/springframework/cloud/context/refresh/ContextRefresher.html)。
#### Endpoint 信息查看
Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Spring Cloud Alibaba Nacos Config Starter 也支持这一点。
在使用之前需要在 maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。
Spring Boot 3.x 可以通过访问 http://127.0.0.1:18084/actuator/nacosconfig 来访问。

如上图所示,Sources 表示此客户端从哪些 Nacos Config 配置项中获取了信息,RefreshHistory 表示动态刷新的历史记录,最多保存20条,NacosConfigProperties 则为 Nacos Config Starter 本身的配置。
#### More
##### 更多配置项
配置项|key|默认值|说明
----|----|-----|-----
服务端地址|spring.cloud.nacos.config.server-addr||服务器ip和端口
DataId前缀|spring.cloud.nacos.config.prefix|${spring.application.name}|DataId的前缀,默认值为应用名称
Group|spring.cloud.nacos.config.group|DEFAULT_GROUP|
DataId后缀及内容文件格式|spring.cloud.nacos.config.file-extension|properties|DataId的后缀,同时也是配置内容的文件格式,目前只支持 properties
配置内容的编码方式|spring.cloud.nacos.config.encode|UTF-8|配置的编码
获取配置的超时时间|spring.cloud.nacos.config.timeout|3000|单位为 ms
配置的命名空间|spring.cloud.nacos.config.namespace||常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源隔离等。
AccessKey|spring.cloud.nacos.config.access-key||
SecretKey|spring.cloud.nacos.config.secret-key||
相对路径|spring.cloud.nacos.config.context-path||服务端 API 的相对路径
接入点|spring.cloud.nacos.config.endpoint||地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否开启监听和自动刷新|spring.cloud.nacos.config.refresh-enabled|true|
集群服务名|spring.cloud.nacos.config.cluster-name||
是否开启 Nacos Config 的 Health Indicator|spring.nacos.config.health-indicator.enabled|false|
是否开启 Nacos Discovery 的 Health Indicator|spring.cloud.nacos.discovery.health-indicator.enabled|false|
### Spring Cloud Alibaba Nacos Discovery
#### 如何接入
在启动 Nacos Discovery 示例进行演示之前,了解一下 Spring Cloud 应用如何接入 Nacos Discovery。
**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。**
1. 首先,修改 `pom.xml` 文件,引入 spring-cloud-alibaba-nacos-discovery-starter;
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery
```
2. 在应用的 `/src/main/resources/application.properties` 配置文件中配置 Nacos Server 地址;
```properties
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
```
3. 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能;
```java
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
@RestController
class EchoController {
@GetMapping(value = "/echo/{string}")
public String echo(@PathVariable String string) {
return string;
}
}
}
```
#### 应用启动
1. 增加配置,在 nacos-discovery-provider-example 项目的 `/src/main/resources/application.properties` 中添加基本配置信息;
```properties
spring.application.name=service-provider
server.port=18082
```
2. 启动应用,支持 IDE 直接启动和编译打包后启动。
1. IDE直接启动:找到 nacos-discovery-provider-example 项目的主类 `ProviderApplication`,执行 main 方法启动应用。
2. 打包编译后启动:在 nacos-discovery-provider-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-discovery-provider-example.jar`启动应用。
#### 查询服务验证
> **注意:需要替换 accessToken!**
在浏览器输入此地址 `http://127.0.0.1:8848/nacos/v1/ns/catalog/instances?accessToken=XXXXXXXXXXXXXXXXXXXXXX&serviceName=service-provider&clusterName=DEFAULT&pageSize=10&pageNo=1&namespaceId=`,并点击跳转,可以看到服务节点已经成功注册到 Nacos Server。

#### 服务发现集成 Spring Cloud Loadbalancer
```xml
org.springframework.cloudspring-cloud-loadbalancer
```
增加如下配置,使用 Spring Cloud Alibaba 社区针对 Spring Cloud Loadbalancer 负载均衡依赖提供的负载均衡策略,以便使用 Spring Cloud Alibaba 提供的所有的能力:
```properties
spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.nacos.enabled=true
```
#### IPv4 至 IPv6 地址迁移方案
##### IPv4 和 IPv6 地址双注册
在配置完成 Spring Cloud Loadbalancer 作为负载均衡策略后,应用启动后会默认将微服务的 IPv4 地址和 IPv6 地址注册到注册中心中,其中 IPv4 地址会存放在 Nacos 服务列表中的 IP 字段下,IPv6 地址在 Nacos 的 metadata 字段中,其对应的 Key 为 IPv6。当服务消费者调用服务提供者时,会根据自身的 IP 地址栈支持情况,选择合适的 IP 地址类型发起服务调用。具体规则:
(1)服务消费者本身支持 IPv4 和 IPv6 双地址栈或仅支持 IPv6 地址栈的情况下,服务消费者会使用服务提供的 IPv6 地址发起服务调用,IPv6 地址调用失败如本身还同时支持 IPv4 地址栈时,暂不支持切换到 IPv4 再发起重试调用;
(2)服务消费者本身仅支持 IPv4 单地址栈的情况下,服务消费者会使用服务提供的 IPv4 地址发起服务调用。
##### 仅注册 IPv4
如果您只想使用 IPv4 地址进行注册,可以在 application.properties 使用以下配置:
```properties
spring.cloud.nacos.discovery.ip-type=IPv4
```
##### 仅注册 IPv6
如果您只想使用 IPv6 地址,可以在 application.properties 使用以下配置:
```properties
spring.cloud.nacos.discovery.ip-type=IPv6
```
#### 使用 RestTemplate 和 FeignClient
下面将分析 nacos-discovery-consumer-example 项目的代码,演示如何 RestTemplate 与 FeignClient。
**注意 本章节只是为了便于理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。此处只涉及 Ribbon、RestTemplate、FeignClient 相关的内容,如果已经使用了其他服务发现组件,可以通过直接替换依赖来接入 Nacos Discovery。**
1. 添加 @LoadBalanced 注解,使得 RestTemplate 接入 Ribbon
```java
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
```
2. FeignClient 已经默认集成了 Ribbon ,此处演示如何配置一个 FeignClient。
```java
@FeignClient(name = "service-provider")
public interface EchoService {
@GetMapping(value = "/echo/{str}")
String echo(@PathVariable("str") String str);
}
```
使用 @FeignClient 注解将 EchoService 这个接口包装成一个 FeignClient,属性 name 对应服务名 service-provider。
echo 方法上的 @RequestMapping 注解将 echo 方法与 URL "/echo/{str}" 相对应,@PathVariable 注解将 URL 路径中的 `{str}` 对应成 echo 方法的参数 str。
3. 完成以上配置后,将两者自动注入到 TestController 中。
```java
@RestController
public class TestController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private EchoService echoService;
@GetMapping(value = "/echo-rest/{str}")
public String rest(@PathVariable String str) {
return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);
}
@GetMapping(value = "/echo-feign/{str}")
public String feign(@PathVariable String str) {
return echoService.echo(str);
}
}
```
4. 配置必要的配置,在 nacos-discovery-consumer-example 项目的 `/src/main/resources/application.properties` 中添加基本配置信息
```properties
spring.application.name=service-consumer
server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.fail-fast=true
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
```
5.启动应用,支持 IDE 直接启动和编译打包后启动。
1. IDE 直接启动:找到 nacos-discovery-consumer-example 项目的主类 `ConsumerApplication`,执行 main 方法启动应用。
2. 打包编译后启动:在 nacos-discovery-consumer-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-discovery-consumer-example.jar` 启动应用。
#### 验证
1. 在浏览器地址栏中输入 [http://127.0.0.1:18083/echo-rest/1234](http://127.0.0.1:18083/echo-rest/1234),点击跳转,可以看到浏览器显示了 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 1234",证明服务发现生效。

2. 在浏览器地址栏中输入 [http://127.0.0.1:18083/echo-feign/12345](http://127.0.0.1:18083/echo-feign/12345),点击跳转,可以看到浏览器显示 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 12345",证明服务发现生效。

#### 原理
##### 服务注册
Spring Cloud Alibaba Nacos Discovery 遵循了 Spring Cloud Common 标准,实现了 AutoServiceRegistration、ServiceRegistry、Registration 这三个接口。
在 Spring Cloud 应用的启动阶段,监听了 WebServerInitializedEvent 事件,当 Web 容器初始化完成后,即收到 WebServerInitializedEvent 事件后,会触发注册的动作,调用 ServiceRegistry 的 register 方法,将服务注册到 Nacos Server。
#### Endpoint 信息查看
Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Spring Cloud Alibaba Nacos Discovery Starter 也支持这一点。
在使用之前需要在 maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。
Spring Boot 3.x 可以通过访问 http://127.0.0.1:18083/actuator/nacos-discovery 来访问。

如上图所示,NacosDiscoveryProperties 则为 Spring Cloud Alibaba Nacos Discovery 本身的配置,也包括本机注册的内容,subscribe 为本机已订阅的服务信息。
#### More
##### 更多配置项
配置项|key|默认值|说明
----|----|-----|-----
服务端地址|spring.cloud.nacos.discovery.server-addr||
服务名|spring.cloud.nacos.discovery.service|${spring.application.name}|注册到Nacos上的服务名称,默认值为应用名称
权重|spring.cloud.nacos.discovery.weight|1|取值范围 1 到 100,数值越大,权重越大
网卡名|spring.cloud.nacos.discovery.network-interface||当IP未配置时,注册的IP为此网卡所对应的IP地址,如果此项也未配置,则默认取第一块网卡的地址
注册的IP地址|spring.cloud.nacos.discovery.ip||优先级最高
注册的IP地址类型|spring.cloud.nacos.discovery.ip-type|双栈地址|可以配置IPv4和IPv6两种类型,如果网卡同类型IP地址存在多个,希望制定特定网段地址,可使用`spring.cloud.inetutils.preferred-networks`配置筛选地址
注册的端口|spring.cloud.nacos.discovery.port|-1|默认情况下不用配置,会自动探测
命名空间|spring.cloud.nacos.discovery.namespace||常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
AccessKey|spring.cloud.nacos.discovery.access-key||
SecretKey|spring.cloud.nacos.discovery.secret-key||
Metadata|spring.cloud.nacos.discovery.metadata||使用Map格式配置
日志文件名|spring.cloud.nacos.discovery.log-name||
集群|spring.cloud.nacos.discovery.cluster-name|DEFAULT|Nacos集群名称
接入点|spring.cloud.nacos.discovery.endpoint||地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否集成LoadBalancer|spring.cloud.loadbalancer.nacos.enabled|false|
是否开启Nacos Watch|spring.cloud.nacos.discovery.watch.enabled|false|可以设置成true来开启 watch
是否启用Nacos|spring.cloud.nacos.discovery.enabled|true|默认启动,设置为false时会关闭自动向Nacos注册的功能
### Spring Cloud Alibaba Nacos 集成 Spring Cloud Gateway
#### 如何接入
在启动示例进行演示之前,了解一下 Spring Cloud 应用如何接入 Spring Cloud 如何接入 Nacos Discovery、Spring Cloud Gateway。
**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。**
1. 首先,修改 `pom.xml` 文件,引入 Spring Cloud Alibaba Nacos Discovery Starter、Spring Cloud Gateway Starter。
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-gateway-server-webflux
```
2. 在应用的 `/src/main/resources/application.properties` 配置文件中配置 Nacos Server 地址
```properties
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
```
3. 在应用的 `/src/main/resources/application.properties` 配置文件中配置 Spring Cloud Gateway 路由
```properties
spring.cloud.gateway.server.webflux.routes[0].id=nacos-route
spring.cloud.gateway.server.webflux.routes[0].uri=lb://service-gateway-provider
spring.cloud.gateway.server.webflux.routes[0].predicates[0].name=Path
spring.cloud.gateway.server.webflux.predicates[0].args[pattern]=/nacos/**
spring.cloud.gateway.server.webflux.routes[0].filters[0]=StripPrefix=1
```
4. 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
```java
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
```
#### Spring Cloud Gateway 应用启动
启动应用,支持 IDE 直接启动和编译打包后启动。
1. IDE直接启动:找到 nacos-gateway-discovery-example 项目的主类 `GatewayApplication`,执行 main 方法启动应用。
2. 打包编译后启动:在 nacos-gateway-discovery-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-gateway-discovery-example.jar`启动应用。
#### 服务提供方应用启动
启动应用,支持 IDE 直接启动和编译打包后启动。
1. IDE 直接启动:找到 nacos-gateway-provider-example 项目的主类 `ProviderApplication`,执行 main 方法启动应用。
2. 打包编译后启动:在 nacos-gateway-provider-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-gateway-provider-example.jar`启动应用。
#### 验证
1.
```bash
curl 'http://127.0.0.1:18085/nacos/echo/hello-world'
hello Nacos Discovery hello-world⏎
```
2.
```bash
curl 'http://127.0.0.1:18085/nacos/divide?a=6&b=2'
3⏎
```
## Native Image构建
请参考 Spring Cloud Alibaba 官网中的 [Graalvm 快速开始](https://sca.aliyun.com/zh-cn/docs/2022.0.0.0/user-guide/graalvm/quick-start)
## 更多介绍
Nacos 为用户提供包括动态服务发现,配置管理,服务管理等服务基础设施,帮助用户更灵活,更轻松地构建,交付和管理他们的微服务平台,基于 Nacos, 用户可以更快速的构建以“服务”为中心的现代云原生应用。Nacos 可以和 Spring Cloud、Kubernetes/CNCF、Dubbo 等微服务生态无缝融合,为用户提供更卓越的体验。更多 Nacos 相关的信息,请参考 [Nacos 项目](https://github.com/alibaba/Nacos)。
未来,Spring-Alibaba-Nacos-Config模块将承载更多职责,面向二方中间件组件,对SpringBoot(包括Spring AI)以及SpringCloud应用提供统一的配置托管以及运行时无损轮转功能,面向普通的业务组件,通过@NacosConfig,@NacosConfigListener注解提供灵活易用的配置注入和变更回调能力。
如果您对 Spring Cloud Nacos Discovery 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。
================================================
FILE: spring-cloud-alibaba-examples/nacos-example/readme.md
================================================
# Spring Cloud Alibaba Nacos Example
## Project description
This project demonstrates how to use Spring Cloud Alibaba Nacos related Starters to complete the service discovery and configuration management of Spring Cloud applications.
[Nacos](https://github.com/alibaba/Nacos) It is Alibaba's open source dynamic service discovery, configuration management and service management platform that is easier to build cloud-native applications.
## Nacos Server 3.1.0 is properly configured and started
In Nacos 3.1.0, functions related to user authentication are added. When starting Nacos Server for the first time, it needs to be configured correctly to avoid the problem of startup failure.
### Download Nacos Server
> The Nacos server version used in this example is 3.1.0!
Nacos supports both direct download and source code construction. **Nacos Server version 3.1.0 is recommended for Spring Cloud Alibaba 2022.x.**
1. Direct download: [Nacos Server download page](https://github.com/alibaba/nacos/releases)
2. Source code construction: Enter Nacos [Github project page](https://github.com/alibaba/nacos), git clone the code to the local compilation and packaging [参考文档](https://nacos.io/zh-cn/docs/quick-start.html).
### Configure the Nacos Server
Open the `\nacos-server-3.1.0\conf\application.properties` configuration file and modify the following configuration items:
#### Configure the data source
Take the MySQL database as an example here, and use the `nacos-server-3.1.0\conf\mysql-schema.sql` initialization database table file. Modify the following configuration as well
```properties
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
db.user.0=root
db.password.0=root
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
```
#### Turn on authentication
**Note: If it is not enabled, login failure exception will occur in 3.1.0!**
```properties
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=true
```
#### Set the server authentication key
```properties
nacos.core.auth.server.identity.key=test
nacos.core.auth.server.identity.value=test
```
#### Set the default token
```properties
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
```
** When using the Nacos service discovery and configuration function, be sure to configure `username` and `password` attribute, otherwise the user will not be found! **
#### Open API authentication
Authentication is required when using the Open api interface in nacos server 3.1.0: For more details, please refer to: [Nacos api authentication](https://nacos.io/zh-cn/docs/auth.html)
1. Obtain accessToken: Use username and password to log in to the nacos server:
`curl -X POST '127.0.0.1:8848/nacos/v1/auth/login' -d 'username=nacos&password=nacos'`
If the username and password are correct, the returned information is as follows:
`{"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYwNTYyOTE2Nn0.2TogGhhr11_vLEjqKko1HJHUJEmsPuCxkur-CfNojDo", "tokenTtl": 18000, "globalAdmin": true}`
2. Use accessToken to request the nacos api interface:
`curl -X GET '127.0.0.1:8848/nacos/v1/cs/configs?accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYwNTYyMzkyM30.O-s2yWfDSUZ7Svd3Vs7jy9tsfDNHs1SuebJB4KlNY8Q&dataId=nacos.example.1&group=nacos_group'`
### Start the Nacos Server
1. Start Nacos Server, enter the folder after downloading to the local and decompressing (enter the folder after compiling and packaging by using the source code construction method), then enter its relative folder `nacos/bin`, and execute the following command according to the actual situation of the operating system. [详情参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。
1. Linux/Unix/Mac operating system, execute the command
`sh startup.sh -m standalone`
2. Windows operating system, executing command
`cmd startup.cmd`
2. Access Nacos Server Console.
The browser enters the address http://127.0.0.1:8848/nacos , **The first login needs to bind the nacos user, because the new version adds authentication, and the user name and password need to be configured during application registration and configuration binding.**
## Nacos application example
### Spring Cloud Alibaba Nacos Config
#### Configuration Update Instructions
In version 2023.0.1.3, to support integration with Nacos Configuration Center in Spring Boot applications and to enable annotations such as `@NacosConfig` and `@NacosConfigListener` based on the original `nacos config` module, the `spring-cloud-starter-alibaba-nacos-config` module has been split into two:
- **spring-alibaba-nacos-config**: Depends only on Spring Boot and can be used independently in non-Spring Cloud applications.
- **spring-cloud-starter-alibaba-nacos-config**: Retains only the components that depend on Spring Cloud.
During the module refactoring, it was observed that as the code evolved, multiple branches of configuration loading logic emerged. This includes the original approach of concatenating `spring.application.name` with `fileExtension` and loading configurations via `share-configs`, `extension-configs`, and `spring.config.import`. These different property sources were loaded at inconsistent times, resulting in **fragmented logic that hinders the extensibility of the configuration module**.
To improve code maintainability, the configuration loading logic has been streamlined, retaining only the **`spring.config.import` standard configuration import mechanism**, which was introduced in **Spring Boot 2.4.0 (November 12, 2020)**. In that release, Spring also **recommended deprecating the bootstrap mode** and encouraged unifying configuration into **`application.properties`**.
For configurations previously loaded using the `application.name` concatenation approach or via `share-configs`, `extension-configs`, etc., you now need to **migrate to using the `spring.config.import`** mechanism for configuration import.
**The standard usage for integrating with NacosConfig is as follows**:
- Importing a Single Configuration
```
spring:
config:
import:nacos:application.propertise?refreshEnabled=true&group=DEFAULT_GROUP
cloud:
nacos:
config:
serverAddr: {nacos server addr}
namespace: {nacos namespace id}
```
- Importing Multiple Configurations
```
spring:
config:
import:
- nacos:application.propertise?group=refreshEnabled=true&group=DEFAULT_GROUP
- nacos:{other config data id}?group={other config group}&refreshEnabled=true
cloud:
nacos:
config:
serverAddr: {nacos server addr}
namespace: {nacos namespace id}
```
#### Application access
Before starting the application sample to demonstrate the project function, first understand how the Spring Cloud application accesses Nacos Config as the service configuration center.
**Note that this section is only for the convenience of understanding the access method. The access work has been completed in this sample code, and no further modification is required.**
1. First, modify the `pom.xml` file to introduce spring-cloud-starter-alibaba-nacos-config;
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-nacos-config
```
2. Configuring a Nacos address in an `/src/main/resources/application.yaml` applied configuration file and introducing a service configuration;
```yml
spring:
cloud:
nacos:
serverAddr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
config:
import:
- nacos:nacos-config-example.properties?refreshEnabled=true&group=DEFAULT_GROUP
```
3. After completing the above two steps, the application will obtain the corresponding configuration from Nacos Server and add it to the Property Sources of Spring Environment. There are four ways to save a portion of the Nacos configuration using the Nacos Configuration Center:
- BeanAutoRefres hConfig Example: An example of supporting automatic refresh of configuration changes by configuring configuration information as beans;
- ConfigListenerEx ample: example of monitoring configuration information;
- Docking Interface Example: An example of docking the Nacos interface and completing the addition, deletion, modification and query of the configuration information through the interface;
- ValueAnnotation Example: An example of obtaining configuration information through the @ Value annotation.
#### Add Configuration in Nacos Server
Add a configuration to the Nacos Server by executing the following command from the command line. **Can be injected directly through the Nacos console!**
```shell
$ curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?accessToken=XXXXXXXXXXXXXXXXXXXXXXXXXXX&dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=spring.cloud.nacos.config.serverAddr=127.0.0.1:8848%0Aspring.cloud.nacos.config.prefix=PREFIX%0Aspring.cloud.nacos.config.group=GROUP%0Aspring.cloud.nacos.config.namespace=NAMESPACE"
```
Details of the added configuration are as follows:
```properties
# dataId is nacos-config-example.properties
# group is DEFAULT_GROUP
# content is:
spring.cloud.nacos.config.serveraddr=127.0.0.1:8848
spring.cloud.nacos.config.prefix=PREFIX
spring.cloud.nacos.config.group=GROUP
spring.cloud.nacos.config.namespace=NAMESPACE
```
#### The application starts
1. Add configuration, and add basic configuration information in the application `/src/main/resources/application.yml`;
```yml
server:
port: 18084
management:
endpoints:
web:
exposure:
include: '*'
```
2. Start the application, support IDE direct start and start after compilation and packaging.
1. IDE direct startup: find the main class `NacosConfigApplication` and execute the main method to start the application.
2. Start after packaging and compiling: First `mvn clean package`, compile and package the project, and then enter the `target` folder to `java -jar nacos-config-example.jar` start the application.
#### Validate
##### Verify automatic injection
Enter `http://127.0.0.1:18084/nacos/bean` in the browser address bar and click turn around to see that the data is successfully obtained from the Nacos Server.

##### Verify dynamic refresh
1. Execute the following command to modify the configuration data on the Nacos Server side
```shell
$ curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?accessToken=XXXXXXXXXXXXXXXXXXXXXXXXXXX&dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=spring.cloud.nacos.config.serveraddr=127.0.0.1:8848%0Aspring.cloud.nacos.config.prefix=PREFIX%0Aspring.cloud.nacos.config.group=DEFAULT_GROUP%0Aspring.cloud.nacos.config.namespace=NAMESPACE"
```
2. Type `http://127.0.0.1:18084/nacos/bean` in the address bar of the browser and click Turn, and you can see that the application obtains the latest data from the Nacos Server, and the group becomes the DEFAULT _ GROUP.

#### Principle
##### Nacos Config Data Structure
Nacos Config uniquely identifies a piece of configuration primarily by dataId and group, assuming you already know this background. If you don't know, please refer to [Nacos 文档](https://nacos.io/zh-cn/docs/concepts.html).
When the Nacos Client obtains data from the Nacos Server, it calls this interface `ConfigService.getConfig(String dataId, String group, long timeoutMs)`.
##### Spring Cloud App Get Data
###### dataID
In the Nacos Config Starter, the concatenation format of dataId is as follow
${prefix} - ${spring.profiles.active} . ${file-extension}
* The `prefix` default value is `spring.application.name`. It can also be configured through configuration items `spring.cloud.nacos.config.prefix`.
* `spring.profiles.active` This is the profile corresponding to the current environment. For details, please refer to
** Note that when the active profile is empty, the corresponding connector `-` does not exist, and the concatenation format of dataId becomes `${prefix}`. `${file-extension}` **
* `file-extension` It is used to configure the data format of content, which can be configured by configuration item `spring.cloud.nacos.config.file-extension`. Currently only types are supported `properties`.
###### group
* `group` The default is `DEFAULT_GROUP`, which can be `spring.cloud.nacos.config.group` configured.
##### Automatic injection
The Spring Cloud Alibaba Nacos Config Starter implements the `org.springframework.boot.context.config.ConfigDataLoader` interface and sets the priority to the highest.
During the Spring Cloud application startup phase, it will actively obtain the corresponding data from the Nacos Server side, convert the obtained data into PropertySource, and inject it into the Property Sources attribute of the Environment. Therefore, the @ Value annotation can also be used to directly obtain the contents of the Nacos Server configuration.
##### Dynamic refresh
By default, the Nacos Config Starter is a refresh method that is triggered `org.springframework.cloud.context.refresh.ContextRefresher` in real time when the monitoring function is added to the configuration item of all Nacos that have successfully obtained data and changes in the server configuration are monitored.
If you need to refresh the Bean dynamically, refer to the Spring and Spring Cloud specifications. It is recommended that you add `@RefreshScope` or `@ConfigurationProperties ` annotate the class,
For more details, please refer to [ContextRefresher Java Doc](http://static.javadoc.io/org.springframework.cloud/spring-cloud-context/2.0.0.RELEASE/org/springframework/cloud/context/refresh/ContextRefresher.html).
#### Endpoint information viewing
Spring Boot applications support the use of Endpoints to expose relevant information, as does the Spring Cloud Alibaba Nacos Config Starter.
Before using it, you need to add `spring-boot-starter-actuator` a dependency in Maven and allow Endpoints access in the configuration.
Spring Boot 3.x can be accessed by visiting http://127.0.0.1:18084/actuator/nacosconfig .

As shown in the figure above, Sources indicates which Nacos Config configuration items the client has obtained information from, and RefreshHistory indicates the history of dynamic refresh, with a maximum of 20 entries saved. NacosConfig Properties is the configuration of the Nacos Config Starter itself.
#### More
##### More configuration items
Configuration item | key | Default value | Description
----|----|-----|-----
Server address | spring. Cloud. Nacos. Config. Server-addr | | server IP and port
Prefix of DataId | spring. Cloud. Nacos. Config. Prefix | ${ spring. Application. Name } | Prefix of DataId. The default value is the application name
Group|spring.cloud.nacos.config.group|DEFAULT_GROUP|
Suffix of DataId and content file format | spring. Cloud. Nacos. Config. File -extension | properties | Suffix of DataId, which is also the file format of configuration content. Currently, only properties is supported
Encoding method of the configured content | spring. Cloud. Nacos. Config. Encode | UTF-8 | Configured encoding
| Obtain the configured timeout | spring. Cloud. Nacos. Config. Timeout | 3000 | Unit: ms |
Namespace of configuration | spring. Cloud. Nacos. Config. Namespace | | One of the common scenarios is to distinguish and isolate the configurations of different environments, such as the resource isolation between the development and testing environments and the production environment.
AccessKey|spring.cloud.nacos.config.access-key||
SecretKey|spring.cloud.nacos.config.secret-key||
Relative path | spring. Cloud. Nacos. Config. Context-path | | Relative path of the server API
Access point | spring. Cloud. Nacos. Config. Endpoint | | The domain name of a service in a region. The server address can be obtained dynamically through this domain name
Whether to enable listening and automatic refresh | spring. Cloud. Nacos. Config. Refresh -enabled | true |
Cluster service name | spring. Cloud. Nacos. Config. Cluster -name | |
Whether to enable nacos-config health indicator |spring.nacos.config.health-indicator.enabled|false|
Whether to enable nacos-discovery health indicator |spring.cloud.nacos.discovery.health-indicator.enabled|false|
### Spring Cloud Alibaba Nacos Discovery
#### How to access
Before launching the Nacos Discovery sample for demonstration, take a look at how Spring Cloud applications access Nacos Discovery.
**Note that this section is only for your convenience to understand the access method. The access work has been completed in this sample code, and you do not need to modify it.**
1. First, modify the `pom.xml` file and introduce spring-cloud-alibaba-nacos-discovery-starter;
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery
```
2. Configuring a Nacos Server address in an `/src/main/resources/application.properties` applied configuration file;
```properties
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
```
3. Use @ EnableDiscoveryClient annotation to enable service registration and discovery;
```java
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
@RestController
class EchoController {
@GetMapping(value = "/echo/{string}")
public String echo(@PathVariable String string) {
return string;
}
}
}
```
#### The application starts
1. Add the configuration, and add the basic configuration information in the nacos-discovery-provider-example project `/src/main/resources/application.properties`;
```properties
spring.application.name=service-provider
server.port=18082
```
2. Start the application, support IDE direct start and start after compilation and packaging.
1. IDE direct startup: Find the main class `ProviderApplication` of the nacos-discovery-provider-example project, and execute the main method to start the application.
2. Start after compilation: Compile and package `mvn clean package` the project in the nacos-discovery-provider-example project, and then `java -jar nacos-discovery-provider-example.jar` start the application.
#### Query service validation
Enter this address `http://127.0.0.1:8848/nacos/v1/ns/catalog/instances?accessToken=XXXXXXXXXXXXXXXXXXXXXXXXXXX&serviceName=service-provider&clusterName=DEFAULT&pageSize=10&pageNo=1&namespaceId=` in the browser and click Jump to see that the service node has been successfully registered to the Nacos Server.

#### Service discovery integration Spring Cloud Loadbalancer.
```xml
org.springframework.cloudspring-cloud-loadbalancer
```
Add the following configuration to use the load balancing strategy provided by the Spring Cloud Alibaba community for Spring Cloud Loadbalancer load balancing dependencies, so as to use all the capabilities provided by the Spring Cloud Alibaba:
```properties
spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.nacos.enabled=true
```
#### IPv4 to IPv6 address migration schema
##### Dual registration of IPv4 and IPv6 addresses
After configuring the Spring Cloud Loadbalancer as a load balancing strategy, the application will register the IPv4 address and IPv6 address of the microservice in the registration center by default after starting, where the IPv4 address will be stored under the IP field in the Nacos service list. The IPv6 address is in the metadata field of Nacos, and its corresponding Key is IPv6. When the service consumer calls the service provider, it will select the appropriate IP address type to initiate the service call according to its own IP address stack support. Specific rules: (1) If the service consumer itself supports both IPv4 and IPv6 address stacks or only supports IPv6 address stacks, the service consumer will use the IPv6 address provided by the service to initiate a service call. If the IPv6 address call fails, if it also supports IPv4 address stacks, (2) When the service consumer itself only supports IPv4 single address stack, the service consumer will use the IPv4 address provided by the service to initiate a service call.
##### Register IPv4 only
If you want to register using only IPv4 addresses, you can use the following configuration at the application. Properties:
```properties
spring.cloud.nacos.discovery.ip-type=IPv4
```
##### Register for IPv6 only
If you want to use only IPv6 addresses, you can use the following configuration on the application. Properties:
```properties
spring.cloud.nacos.discovery.ip-type=IPv6
```
#### Using RestTemplate and FeignClient
Here's a look at the code for the nacos-discovery-consumer-example project to show how to RestTemplate and FeignClient.
**Note that this section is only for the convenience of understanding the access method. The access work has been completed in this sample code, and you do not need to modify it. Only Ribbon, RestTemplate and FeignClient are involved here. If other service discovery components have been used, Nacos Discovery can be accessed by directly replacing dependencies.**
1. Add the @ LoadBalanced annotation to make the RestTemplate access the Ribbon
```java
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
```
2. FeignClient has been integrated with Ribbon by default. Here is how to configure a FeignClient.
```java
@FeignClient(name = "service-provider")
public interface EchoService {
@GetMapping(value = "/echo/{str}")
String echo(@PathVariable("str") String str);
}
```
Use the @ FeignClient annotation to wrap the Echo Service interface as a FeignClient, and the attribute name corresponds to the service name service-provider.
The @ RequestMapping annotation on the echo method corresponds the echo method to the URL "/echo/{ str}", and the @ PathVariable annotation corresponds the str in `{str}` the URL path to the parameter of the echo method.
3. After the above configuration is completed, the two are automatically injected into the TestController.
```java
@RestController
public class TestController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private EchoService echoService;
@GetMapping(value = "/echo-rest/{str}")
public String rest(@PathVariable String str) {
return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);
}
@GetMapping(value = "/echo-feign/{str}")
public String feign(@PathVariable String str) {
return echoService.echo(str);
}
}
```
4. Configure the necessary configuration and add the basic configuration information in the nacos-discovery-consumer-example project `/src/main/resources/application.properties`.
```java
@RestController
public class TestController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private EchoService echoService;
@GetMapping(value = "/echo-rest/{str}")
public String rest(@PathVariable String str) {
return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);
}
@GetMapping(value = "/echo-feign/{str}")
public String feign(@PathVariable String str) {
return echoService.echo(str);
}
}
```
5.Start the application, support IDE direct start and start after compilation and packaging.
1. IDE direct startup: Find the main class `ConsumerApplication` of the nacos-discovery-consumer-example project, and execute the main method to start the application.
2. Start after compilation: Compile and package `mvn clean package` the project in the nacos-discovery-consumer-example project, and then `java -jar nacos-discovery-consumer-example.jar` start the application.
#### Validate
1. Enter [http://127.0.0.1:18083/echo-rest/1234](http://127.0.0.1:18083/echo-rest/1234) and click Go, you can see that the message "hello Nacos Discovery 1234" returned by nacos-discovery-provider-example in the browser address bar to prove that the service discovery is valid.

2. Enter [http://127.0.0.1:18083/echo-feign/12345](http://127.0.0.1:18083/echo-feign/12345) and click Go, you can see that the message "hello Nacos Discovery 12345" returned by nacos-discovery-provider-example in the browser address bar to prove that the service discovery is effective.

#### Principle
##### Service registration
The Spring Cloud Alibaba Nacos Discovery follows the Spring cloud Common standard. The three interfaces of AutoService Registration, Service Registry and Registration are implemented.
In the startup phase of the Spring Cloud application, the WebServerInitializedEvent event is monitored. After the Web container is initialized, that is, after the WebServerInitializedEvent event is received, the registration action is triggered. Call the register method of the Service Registry to register the service with the Nacos Server.
#### Endpoint information viewing
Spring Boot applications support the use of Endpoints to expose relevant information, as does the Spring Cloud Alibaba Nacos Discovery Starter.
Before using it, you need to add `spring-boot-starter-actuator` a dependency in Maven and allow Endpoints access in the configuration.
Spring Boot 3.x can be accessed by visiting http://127.0.0.1:18083/actuator/nacos-discovery .

As shown in the figure above, NacosDiscovery Properties refers to the configuration of the Spring Cloud Alibaba Nacos Discovery itself, including the content registered by the local machine, and subscribe refers to the subscribed service information of the local machine.
#### More
##### More configuration items
Configuration item | key | Default value | Description
----|----|-----|-----
Server address | spring. Cloud. Nacos. Discovery. Server -addr | |
Service Name | spring. Cloud. Nacos. Discovery. Service | ${ spring. Application. Name } | The name of the service registered to Nacos. The default is the application name
Weight | spring. Cloud. Nacos. Discovery. Weight | 1 | Values range from 1 to 100. The larger the value, the greater the weight
Network card name | spring. Cloud. Nacos. Discovery. Network -interface | | When IP is not configured, the registered IP is the IP address corresponding to this network card. If this item is not configured, the address of the first network card is used by default
Registered IP Address | spring. Cloud. Nacos. Discovery. IP | | Highest Priority
Registered IP address type | spring. Cloud. Nacos. Discovery. IP -type | Dual stack address | Both IPv4 and IPv6 types can be configured. If there are multiple IP addresses of the same type in the network card and you want to designate a specific network segment address, you can configure the filtering address with `spring.cloud.inetutils.preferred-networks`
Registered port | spring. Cloud. Nacos. Discovery. Port | -1 | is not configured by default and will be detected automatically
Namespace | spring. Cloud. Nacos. Discovery. Namespace | | One of the common scenarios is to distinguish and isolate the registration of different environments, such as the isolation of resources (such as configurations and services) between the development and testing environments and the production environment.
AccessKey|spring.cloud.nacos.discovery.access-key||
SecretKey|spring.cloud.nacos.discovery.secret-key||
Metadata | spring. Cloud. Nacos. Discovery. Metadata | | Configure using Map format
Log file name | spring. Cloud. Nacos. Discovery. Log -name | |
Cluster | spring. Cloud. Nacos. Discovery. Cluster -name | DEFAULT | Nacos cluster name
Access point | spring. Cloud. Nacos. Discovery. Endpoint | | The domain name of a service in a region. The server address can be obtained dynamically through this domain name
Integrate LoadBalancer | spring. Cloud. Loadbalancer. Nacos. Enabled | false |
Nacos Watch enabled | spring. Cloud. Nacos. Discovery. Watch. Enabled | false | can be set to true to enable watch
Enable Nacos | spring. Cloud. Nacos. Discovery. Enabled | true | Start by default. If set to false, automatic registration with Nacos will be disabled
### Spring Cloud Alibaba Nacos integrated Spring Cloud Gateway.
#### How to access
Before starting the demo, learn how Spring Cloud applications connect to Spring Cloud, Nacos Discovery, and Spring Cloud Gateway.
**Note that this section is only for your convenience to understand the access method. The access work has been completed in this sample code, and you do not need to modify it.**
1. First, modify the `pom.xml` file to introduce Spring Cloud Alibaba Nacos Discovery Starter and Spring Cloud Gateway Starter.
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-gateway-server-webflux
```
2. Configure the Nacos Server address in the applied `/src/main/resources/application.properties` configuration films
```properties
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
```
3. Configure Spring Cloud Gateway routing in the application's `/src/main/resources/application.properties` configuration file
```properties
spring.cloud.gateway.server.webflux.routes[0].id=nacos-route
spring.cloud.gateway.server.webflux.routes[0].uri=lb://service-gateway-provider
spring.cloud.gateway.server.webflux.routes[0].predicates[0].name=Path
spring.cloud.gateway.server.webflux.routes[0].predicates[0].args[pattern]=/nacos/**
spring.cloud.gateway.server.webflux.routes[0].filters[0]=StripPrefix=1
```
4. Use the @ EnableDiscoveryClient annotation to turn on service registration and discovery
```java
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
```
#### Spring Cloud Gateway App Launch
Start the application, support IDE direct start and start after compilation and packaging.
1. IDE direct startup: Find the main class `GatewayApplication` of the nacos-gateway-discovery-example project, and execute the main method to start the application.
2. Start after compilation: Compile and package `mvn clean package` the project in the nacos-gateway-discovery-example project, and then `java -jar nacos-gateway-discovery-example.jar` start the application.
#### Service Provider Application Launch
Start the application, support IDE direct start and start after compilation and packaging.
1. Start the IDE directly: find the main class `ProviderApplication` of the nacos-gateway-provider-example project, and execute the main method to start the application.
2. Start after compilation: Compile and package `mvn clean package` the project in the nacos-gateway-provider-example project, and then `java -jar nacos-gateway-provider-example.jar` start the application.
#### Validate
1.
```bash
curl 'http://127.0.0.1:18085/nacos/echo/hello-world'
hello Nacos Discovery hello-world⏎
```
2.
```bash
curl 'http://127.0.0.1:18085/nacos/divide?a=6&b=2'
3⏎
```
## Native Image build
Please refer to the Spring Cloud Alibaba website
## More introduction
Nacos provides users with service infrastructure including dynamic service discovery, configuration management, service management, etc., to help users build, deliver and manage their microservice platforms more flexibly and easily. Based on Nacos, users can build modern cloud native applications centered on "services" more quickly. Nacos can be seamlessly integrated with Spring Cloud, Kubernetes/CNCF, Dubbo and other micro-service ecosystems to provide users with a better experience. For more information about Nacos, see the [Nacos 项目](https://github.com/alibaba/Nacos).
In the future, the **Spring-Alibaba-Nacos-Config** module will take on more responsibilities. It will serve as a unified configuration management solution for both second-party middleware components and business components. For **Spring Boot** (including **Spring AI**) and **Spring Cloud** applications, it will provide centralized configuration hosting and seamless runtime configuration rotation. For general business components, it will offer flexible and user-friendly configuration injection and change callback capabilities through the `@NacosConfig` and `@NacosConfigListener` annotations.
If you have any suggestions or ideas about Spring Cloud Nacos Discovery, please feel free to send them to us in the issue or through other community channels.
================================================
FILE: spring-cloud-alibaba-examples/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba${revision}../pom.xml4.0.0spring-cloud-alibaba-examplespomSpring Cloud Alibaba ExamplesExample showing how to use features of Spring Cloud Alibabasentinel-example/sentinel-core-examplesentinel-example/sentinel-openfeign-examplesentinel-example/sentinel-resttemplate-examplesentinel-example/sentinel-circuitbreaker-examplesentinel-example/sentinel-webflux-examplesentinel-example/sentinel-spring-cloud-gateway-examplenacos-example/nacos-discovery-examplenacos-example/nacos-config-examplenacos-example/nacos-gateway-exampleseata-example/business-serviceseata-example/order-serviceseata-example/storage-serviceseata-example/account-servicerocketmq-example/rocketmq-comprehensive-examplerocketmq-example/rocketmq-orderly-consume-examplerocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-producer-examplerocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer1-examplerocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer2-examplerocketmq-example/rocketmq-delay-consume-examplerocketmq-example/rocketmq-sql-consume-examplerocketmq-example/rocketmq-example-commonrocketmq-example/rocketmq-tx-examplerocketmq-example/rocketmq-pollable-consume-examplespring-cloud-bus-rocketmq-examplespring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-examplespring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-consul-exampleintegrated-example/integrated-storageintegrated-example/integrated-accountintegrated-example/integrated-orderintegrated-example/integrated-gatewayintegrated-example/integrated-praise-providerintegrated-example/integrated-praise-consumerintegrated-example/integrated-commonintegrated-example/integrated-frontendspring-cloud-scheduling-exampleorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}trueorg.graalvm.buildtoolsnative-maven-plugin${native-maven-plugin.version}org.apache.maven.pluginsmaven-javadoc-plugintrueorg.apache.maven.pluginsmaven-source-plugintruenativeorg.springframework.bootspring-boot-maven-plugin
-agentlib:native-image-agent=config-merge-dir=src/main/resources/META-INF/native-image/
paketobuildpacks/builder:tinytrueprocess-aotprocess-aotorg.graalvm.buildtoolsnative-maven-plugin${project.build.outputDirectory}true22.3add-reachability-metadataadd-reachability-metadata
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/readme-zh.md
================================================
# RocketMQ Example
## 项目说明
本项目演示如何使用 RocketMQ Binder 完成 Spring Cloud 应用消息的订阅和发布。
[RocketMQ](https://rocketmq.apache.org/) 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
在说明 RocketMQ 的示例之前,我们先了解一下 Spring Cloud Stream。
这是官方对 Spring Cloud Stream 的一段介绍:
Spring Cloud Stream 是一个用于构建基于消息的微服务应用框架。它基于 SpringBoot 来创建具有生产级别的单机 Spring 应用,并且使用 `Spring Integration` 与 Broker 进行连接。
Spring Cloud Stream 提供了消息中间件配置的统一抽象,推出了 publish-subscribe、consumer groups、partition 这些统一的概念。
Spring Cloud Stream 内部有两个概念:Binder 和 Binding。
* Binder: 跟外部消息中间件集成的组件,用来创建 Binding,各消息中间件都有自己的 Binder 实现。
比如 `Kafka` 的实现 `KafkaMessageChannelBinder`,`RabbitMQ` 的实现 `RabbitMessageChannelBinder` 以及 `RocketMQ` 的实现 `RocketMQMessageChannelBinder`。
* Binding: 包括 Input Binding 和 Output Binding。
Binding 在消息中间件与应用程序提供的 Provider 和 Consumer 之间提供了一个桥梁,实现了开发者只需使用应用程序的 Provider 或 Consumer 生产或消费数据即可,屏蔽了开发者与底层消息中间件的接触。
下图是 Spring Cloud Stream 的架构设计。

## 准备工作
### 下载并启动 RocketMQ
**在接入 RocketMQ Binder 之前,首先需要启动 RocketMQ 的 Name Server 和 Broker。**
1. 下载[RocketMQ最新的二进制文件](https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip),并解压
2. 启动 Name Server
```bash
sh bin/mqnamesrv
```
3. 启动 Broker
```bash
sh bin/mqbroker -n localhost:9876
```
### 引入依赖
修改 `pom.xml` 文件,引入 RocketMQ Stream Starter。
```xml
com.alibaba.cloudspring-cloud-starter-stream-rocketmq
```
## 简单示例
### 创建Topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t test-topic
```
### 示例代码
配置 Input 和 Output 的 Binding 信息并配合 `@EnableBinding` 注解使其生效
```java
@SpringBootApplication
@EnableBinding({ Source.class, Sink.class })
public class RocketMQApplication {
public static void main(String[] args) {
SpringApplication.run(RocketMQApplication.class, args);
}
}
```
配置 Binding 信息:
```properties
# 配置rocketmq的nameserver地址
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
# 定义name为output的binding
spring.cloud.stream.bindings.output.destination=test-topic
spring.cloud.stream.bindings.output.content-type=application/json
# 定义name为input的binding
spring.cloud.stream.bindings.input.destination=test-topic
spring.cloud.stream.bindings.input.content-type=application/json
spring.cloud.stream.bindings.input.group=test-group
```
### 应用启动
1. 增加配置,在应用的 /src/main/resources/application.properties 中添加基本配置信息
```properties
spring.application.name=rocketmq-example
server.port=28081
```
2. 启动应用,支持 IDE 直接启动和编译打包后启动。
1. IDE 直接启动:找到主类 `RocketMQApplication`,执行 main 方法启动应用。
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar rocketmq-example.jar` 启动应用。
### 消息处理
使用 name 为 output 对应的 binding 发送消息到 test-topic 这个 topic。
使用2个 input binding 订阅数据。
* input1: 订阅 topic 为 test-topic 的消息,顺序消费所有消息(顺序消费的前提是所有消息都在一个 MessageQueue 中)
* input2: 订阅 topic 为 test-topic 的消息,异步消费 tags 为 tagStr 的消息,Consumer 端线程池个数为20
配置信息如下:
```properties
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
spring.cloud.stream.bindings.output.destination=test-topic
spring.cloud.stream.bindings.output.content-type=application/json
spring.cloud.stream.bindings.input1.destination=test-topic
spring.cloud.stream.bindings.input1.content-type=text/plain
spring.cloud.stream.bindings.input1.group=test-group1
spring.cloud.stream.rocketmq.bindings.input1.consumer.orderly=true
spring.cloud.stream.bindings.input2.destination=test-topic
spring.cloud.stream.bindings.input2.content-type=text/plain
spring.cloud.stream.bindings.input2.group=test-group2
spring.cloud.stream.rocketmq.bindings.input2.consumer.orderly=false
spring.cloud.stream.rocketmq.bindings.input2.consumer.tags=tagStr
spring.cloud.stream.bindings.input2.consumer.concurrency=20
```
#### 消息发送
使用 MessageChannel 进行消息发送:
```java
public class ProducerRunner implements CommandLineRunner {
@Autowired
private MessageChannel output; // 获取name为output的binding
@Override
public void run(String... args) throws Exception {
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_TAGS, "tagStr");
Message message = MessageBuilder.createMessage(msg, new MessageHeaders(headers));
output.send(message);
}
}
```
或者使用 RocketMQ 原生的 API 进行消息发送:
```java
public class RocketMQProducer {
DefaultMQProducer producer = new DefaultMQProducer("producer_group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
Message msg = new Message("test-topic", "tagStr", "message from rocketmq producer".getBytes());
producer.send(msg);
}
```
#### 消息接收
使用 `@StreamListener` 注解接收消息:
```java
@Service
public class ReceiveService {
@StreamListener("input1")
public void receiveInput1(String receiveMsg) {
System.out.println("input1 receive: " + receiveMsg);
}
@StreamListener("input2")
public void receiveInput2(String receiveMsg) {
System.out.println("input2 receive: " + receiveMsg);
}
}
```
## 广播消费示例
广播会发送消息给所有消费者。如果你想同一消费组下所有消费者接收到同一个topic下的消息,广播消费非常适合此场景。
### 创建Topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t broadcast
```
### 生产者
**application.yml**
```yaml
server:
port: 28085
spring:
application:
name: rocketmq-broadcast-producer-example
cloud:
stream:
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
bindings:
producer-out-0:
destination: broadcast
logging:
level:
org.springframework.context.support: debug
```
**code**
使用`ApplicationRunner`和`StreamBridge`发送消息。
```java
@SpringBootApplication
public class RocketMQBroadcastProducerApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastProducerApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastProducerApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
}
```
### 消费者
启动两个消费者实例。
#### 消费者1
**application.yml**
```yaml
server:
port: 28084
spring:
application:
name: rocketmq-broadcast-consumer1-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
consumer-in-0:
consumer:
messageModel: BROADCASTING
bindings:
consumer-in-0:
destination: broadcast
group: broadcast-consumer
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQBroadcastConsumer1Application {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastConsumer1Application.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastConsumer1Application.class, args);
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer1 Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
```
#### 消费者2
**application.yml**
```yaml
server:
port: 28083
spring:
application:
name: rocketmq-broadcast-consumer2-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
consumer-in-0:
consumer:
messageModel: BROADCASTING
bindings:
consumer-in-0:
destination: broadcast
group: broadcast-consumer
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQBroadcastConsumer2Application {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastConsumer2Application.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastConsumer2Application.class, args);
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer2 Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
```
## 顺序消费示例
顺序消息(FIFO消息)是消息队列RocketMQ版提供的一种严格按照顺序来发布和消费的消息类型。
顺序消息分为两类:
- 全局顺序:对于指定的一个Topic,所有消息按照严格的先入先出FIFO(First In First Out)的顺序进行发布和消费。分区顺序:对于指定的一个Topic,所有消息根据Sharding Key进行区块分区。同一个分区内的消息按照严格的FIFO顺序进行发布和消费。Sharding Key是顺序消息中用来区分不同分区的关键字段,和普通消息的Key是完全不同的概念。
### 创建Topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t orderly
```
### 示例代码
**application.yml**
```yaml
server:
port: 28082
spring:
application:
name: rocketmq-orderly-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
# 定义messageSelector
messageQueueSelector: orderlyMessageQueueSelector
consumer-in-0:
consumer:
# tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } .
subscription: 'TagA || TagC || TagD'
push:
orderly: true
bindings:
producer-out-0:
destination: orderly
consumer-in-0:
destination: orderly
group: orderly-consumer
logging:
level:
org.springframework.context.support: debug
```
**MessageQueueSelector**
选择适合自己的分区选择算法,保证同一个参数得到的结果相同。
```java
@Component
public class OrderlyMessageQueueSelector implements MessageQueueSelector {
private static final Logger log = LoggerFactory
.getLogger(OrderlyMessageQueueSelector.class);
@Override
public MessageQueue select(List mqs, Message msg, Object arg) {
Integer id = (Integer) ((MessageHeaders) arg).get(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID);
String tag = (String) ((MessageHeaders) arg).get(MessageConst.PROPERTY_TAGS);
int index = id % RocketMQOrderlyConsumeApplication.tags.length % mqs.size();
return mqs.get(index);
}
}
```
**生产者&消费者**
```java
@SpringBootApplication
public class RocketMQOrderlyConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQOrderlyConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
/***
* tag array.
*/
public static final String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
public static void main(String[] args) {
SpringApplication.run(RocketMQOrderlyConsumeApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_TAGS, tags[i % tags.length]);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
String tagHeaderKey = RocketMQMessageConverterSupport.toRocketHeaderKey(
MessageConst.PROPERTY_TAGS).toString();
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " TAG:" +
msg.getHeaders().get(tagHeaderKey).toString());
try {
Thread.sleep(100);
}
catch (InterruptedException ignored) {
}
};
}
}
```
## 延时消息示例
- 延时消息:Producer将消息发送到消息队列RocketMQ服务端,但并不期望立马投递这条消息,而是延迟一定时间后才投递到Consumer进行消费,该消息即延时消息。
### 创建Topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t delay
```
### 示例代码
**application.yml**
```yaml
server:
port: 28086
spring:
application:
name: rocketmq-delay-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
bindings:
producer-out-0:
destination: delay
consumer-in-0:
destination: delay
group: delay-group
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQDelayConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQDelayConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQDelayConsumeApplication.class, args);
}
@Bean
public ApplicationRunner producerDelay() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
// 设置延时等级1~10
headers.put(MessageConst.PROPERTY_DELAY_TIME_LEVEL, 2);
Message msg = new GenericMessage(new SimpleMsg("Delay RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
```
## 过滤消息示例
### 创建Topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t sql
```
### 示例代码
**application.yml**
支持tag过滤或者sql过滤,设置`spring.cloud.stream.rocketmq.bindings..consumer.subscription`即可。
tag示例: `tag:red || blue`
sql示例: `sql:(color in ('red1', 'red2', 'red4') and price>3)`
更多请参考: [Filter](https://rocketmq.apache.org/docs/filter-by-sql92-example/)
```yaml
server:
port: 28087
spring:
application:
name: rocketmq-sql-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
consumer-in-0:
consumer:
# tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } .
subscription: sql:(color in ('red1', 'red2', 'red4') and price>3)
bindings:
producer-out-0:
destination: sql
consumer-in-0:
destination: sql
group: sql-group
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQSqlConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQSqlConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQSqlConsumeApplication.class, args);
}
/**
* color array.
*/
public static final String[] color = new String[] {"red1", "red2", "red3", "red4", "red5"};
/**
* price array.
*/
public static final Integer[] price = new Integer[] {1, 2, 3, 4, 5};
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put("color", color[i % color.length]);
headers.put("price", price[i % price.length]);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
String colorHeaderKey = "color";
String priceHeaderKey = "price";
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " COLOR:" +
msg.getHeaders().get(colorHeaderKey).toString() + " " +
"PRICE: " + msg.getHeaders().get(priceHeaderKey).toString());
};
}
}
```
#### 常见问题
- MQClientException: The broker does not support consumer to filter message by SQL92
1. 修改 RocketMQ 服务端配置文件。
在 `conf/2m-2s-async/broker-a.properties` 配置文件末尾添加 `enablePropertyFilter=true`
2. 重启 mqbroker 并指定配置文件。
`mqbroker` 启动时指定配置文件:`conf/2m-2s-async/broker-a.properties`,例如:
```shell
bin/mqbroker -n 127.0.0.1:9876 -c conf/2m-2s-async/broker-a.properties autoCreateTopicEnable=true
```
## 事务消息示例
### 什么是事务消息?
参考[Transaction Example](https://rocketmq.apache.org/docs/transaction-example/).
> 可以被认为是一个两阶段的提交消息实现,以确保分布式系统的最终一致性。 事务性消息确保本地事务的执行和消息的发送可以原子地执行。
### Application
> 1、 事务装填
>
> 事务消息有三个状态:
> (1) TransactionStatus.CommitTransaction: 提交事务,意味着消费者可以消费事务
> (2) TransactionStatus.RollbackTransaction: 回滚事务,消息将被删除,并且不允许被消费。
> (3) TransactionStatus.Unknown: 中间状态,意味着MQ需要回查最终状态。
### 创建Topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t tx
```
### 示例代码
**application.yml**
```yaml
server:
port: 28088
spring:
application:
name: rocketmq-tx-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
transactionListener: myTransactionListener
producerType: Trans
bindings:
producer-out-0:
destination: tx
consumer-in-0:
destination: tx
group: tx-group
logging:
level:
org.springframework.context.support: debug
```
**TransactionListenerImpl**
执行本地事务。
```java
@Component("myTransactionListener")
public class TransactionListenerImpl implements TransactionListener {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Object num = msg.getProperty("test");
if ("1".equals(num)) {
System.out.println("executer: " + new String(msg.getBody()) + " unknown");
return LocalTransactionState.UNKNOW;
}
else if ("2".equals(num)) {
System.out.println("executer: " + new String(msg.getBody()) + " rollback");
return LocalTransactionState.ROLLBACK_MESSAGE;
}
System.out.println("executer: " + new String(msg.getBody()) + " commit");
return LocalTransactionState.COMMIT_MESSAGE;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
System.out.println("check: " + new String(msg.getBody()));
return LocalTransactionState.COMMIT_MESSAGE;
}
}
```
**producer and consumer**
```java
@SpringBootApplication
public class RocketMQTxApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQTxApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQTxApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 1; i <= 4; i++) {
MessageBuilder builder = MessageBuilder.withPayload(new SimpleMsg("Hello Tx msg " + i));
builder.setHeader("test", String.valueOf(i))
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
builder.setHeader(RocketMQConst.USER_TRANSACTIONAL_ARGS, "binder");
Message msg = builder.build();
streamBridge.send("producer-out-0", msg);
System.out.println("send Msg:" + msg.toString());
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
Object arg = msg.getHeaders();
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " ARG:"
+ arg.toString());
};
}
}
```
## Endpoint 信息查看
Spring Boot 应用支持通过 Endpoint 来暴露相关信息,RocketMQ Stream Starter 也支持这一点。
在使用之前需要在 Maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`
Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/rocketmq_binder 来查看 RocketMQ Binder Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:28081/actuator/rocketmq-binder 来访问。
这里会统计消息最后一次发送的数据,消息发送成功或失败的次数,消息消费成功或失败的次数等数据。
```json
{
"runtime": {
"lastSend.timestamp": 1542786623915
},
"metrics": {
"scs-rocketmq.consumer.test-topic.totalConsumed": {
"count": 11
},
"scs-rocketmq.consumer.test-topic.totalConsumedFailures": {
"count": 0
},
"scs-rocketmq.producer.test-topic.totalSentFailures": {
"count": 0
},
"scs-rocketmq.consumer.test-topic.consumedPerSecond": {
"count": 11,
"fifteenMinuteRate": 0.012163847780107841,
"fiveMinuteRate": 0.03614605351360527,
"meanRate": 0.3493213353657594,
"oneMinuteRate": 0.17099243039490175
},
"scs-rocketmq.producer.test-topic.totalSent": {
"count": 5
},
"scs-rocketmq.producer.test-topic.sentPerSecond": {
"count": 5,
"fifteenMinuteRate": 0.005540151995103271,
"fiveMinuteRate": 0.01652854617838251,
"meanRate": 0.10697493212602836,
"oneMinuteRate": 0.07995558537067671
},
"scs-rocketmq.producer.test-topic.sentFailuresPerSecond": {
"count": 0,
"fifteenMinuteRate": 0.0,
"fiveMinuteRate": 0.0,
"meanRate": 0.0,
"oneMinuteRate": 0.0
},
"scs-rocketmq.consumer.test-topic.consumedFailuresPerSecond": {
"count": 0,
"fifteenMinuteRate": 0.0,
"fiveMinuteRate": 0.0,
"meanRate": 0.0,
"oneMinuteRate": 0.0
}
}
}
```
注意:要想查看统计数据需要在pom里加上 [metrics-core依赖](https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core)。如若不加,endpoint 将会显示 warning 信息而不会显示统计信息:
```json
{
"warning": "please add metrics-core dependency, we use it for metrics"
}
```
## More
RocketMQ 是一款功能强大的分布式消息系统,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。
此 Demo 仅演示了 RocketMQ 与 Spring Cloud Stream 结合后的使用,更多 RocketMQ 相关的信息,请参考 [RocketMQ 项目](https://github.com/apache/rocketmq)。
如果您对 spring cloud starter stream rocketmq 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/readme.md
================================================
# RocketMQ Example
## Project Instruction
This example illustrates how to use RocketMQ Binder implement pub/sub messages for Spring Cloud applications.
[RocketMQ](https://rocketmq.apache.org/) is a distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.
Before we start the demo, let's look at Spring Cloud Stream.
Spring Cloud Stream is a framework for building message-driven microservice applications. Spring Cloud Stream builds upon Spring Boot to create standalone, production-grade Spring applications and uses Spring Integration to provide connectivity to message brokers. It provides opinionated configuration of middleware from several vendors, introducing the concepts of persistent publish-subscribe semantics, consumer groups, and partitions.
There are two concepts in Spring Cloud Stream: Binder 和 Binding.
* Binder: A strategy interface used to bind an app interface to a logical name.
Binder Implementations includes `KafkaMessageChannelBinder` of kafka, `RabbitMessageChannelBinder` of RabbitMQ and `RocketMQMessageChannelBinder` of `RocketMQ`.
* Binding: Including Input Binding and Output Binding.
Binding is Bridge between the external messaging systems and application provided Producers and Consumers of messages.
This is a overview of Spring Cloud Stream.

## Preparation
### Download and Startup RocketMQ
You should startup Name Server and Broker before using RocketMQ Binder.
1. Download [RocketMQ](https://archive.apache.org/dist/rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip) and unzip it.
2. Startup Name Server
```bash
sh bin/mqnamesrv
```
3. Startup Broker
```bash
sh bin/mqbroker -n localhost:9876
```
### Declare dependency
Add dependency spring-cloud-starter-stream-rocketmq to the `pom.xml` file in your Spring Cloud project.
```xml
com.alibaba.cloudspring-cloud-starter-stream-rocketmq
```
## Simple example
### Create topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t test-topic
```
### Integration with RocketMQ Binder
Configure Input and Output Binding and cooperate with `@EnableBinding` annotation
```java
@SpringBootApplication
@EnableBinding({ Source.class, Sink.class })
public class RocketMQApplication {
public static void main(String[] args) {
SpringApplication.run(RocketMQApplication.class, args);
}
}
```
Configure Binding:
```properties
# configure the nameserver of rocketmq
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
# configure the output binding named output
spring.cloud.stream.bindings.output.destination=test-topic
spring.cloud.stream.bindings.output.content-type=application/json
# configure the input binding named input
spring.cloud.stream.bindings.input.destination=test-topic
spring.cloud.stream.bindings.input.content-type=application/json
spring.cloud.stream.bindings.input.group=test-group
```
### Start Application
1. Add necessary configurations to file `/src/main/resources/application.properties`.
```properties
spring.application.name=rocketmq-example
server.port=28081
```
2. Start the application in IDE or by building a fatjar.
1. Start in IDE: Find main class `RocketMQApplication`, and execute the main method.
2. Build a fatjar: Execute command `mvn clean package` to build a fatjar, and run command `java -jar rocketmq-example.jar` to start the application.
### Message Handle
Using the binding named output and sent messages to `test-topic` topic.
And using two input bindings to subscribe messages.
* input1: subscribe the message of `test-topic` topic and consume ordered messages(all messages should in the same MessageQueue if you want to consuming ordered messages).
* input2: subscribe the message of `test-topic` topic and consume concurrent messages which tags is `tagStr`, the thread number in pool is 20 in Consumer side.
see the configuration below:
```properties
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
spring.cloud.stream.bindings.output.destination=test-topic
spring.cloud.stream.bindings.output.content-type=application/json
spring.cloud.stream.bindings.input1.destination=test-topic
spring.cloud.stream.bindings.input1.content-type=text/plain
spring.cloud.stream.bindings.input1.group=test-group1
spring.cloud.stream.rocketmq.bindings.input1.consumer.orderly=true
spring.cloud.stream.bindings.input2.destination=test-topic
spring.cloud.stream.bindings.input2.content-type=text/plain
spring.cloud.stream.bindings.input2.group=test-group2
spring.cloud.stream.rocketmq.bindings.input2.consumer.orderly=false
spring.cloud.stream.rocketmq.bindings.input2.consumer.tags=tagStr
spring.cloud.stream.bindings.input2.consumer.concurrency=20
```
#### Pub Messages
Using MessageChannel to send messages:
```java
public class ProducerRunner implements CommandLineRunner {
@Autowired
private MessageChannel output;
@Override
public void run(String... args) throws Exception {
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_TAGS, "tagStr");
Message message = MessageBuilder.createMessage(msg, new MessageHeaders(headers));
output.send(message);
}
}
```
Or you can using the native API of RocketMQ to send messages:
```java
public class RocketMQProducer {
DefaultMQProducer producer = new DefaultMQProducer("producer_group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
Message msg = new Message("test-topic", "tagStr", "message from rocketmq producer".getBytes());
producer.send(msg);
}
```
#### Sub Messages
Using `@StreamListener` to receive messages:
```java
@Service
public class ReceiveService {
@StreamListener("input1")
public void receiveInput1(String receiveMsg) {
System.out.println("input1 receive: " + receiveMsg);
}
@StreamListener("input2")
public void receiveInput2(String receiveMsg) {
System.out.println("input2 receive: " + receiveMsg);
}
}
```
## Broadcasting exmaple
### Create topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t broadcast
```
### Producer
**application.yml**
```yaml
server:
port: 28085
spring:
application:
name: rocketmq-broadcast-producer-example
cloud:
stream:
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
bindings:
producer-out-0:
destination: broadcast
logging:
level:
org.springframework.context.support: debug
```
**code**
Use `ApplicationRunner` and `StreamBridge` to send messages.
```java
@SpringBootApplication
public class RocketMQBroadcastProducerApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastProducerApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastProducerApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
}
```
### Consumer
Startup two consumers.
#### Consumer1
**application.yml**
```yaml
server:
port: 28084
spring:
application:
name: rocketmq-broadcast-consumer1-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
consumer-in-0:
consumer:
messageModel: BROADCASTING
bindings:
consumer-in-0:
destination: broadcast
group: broadcast-consumer
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQBroadcastConsumer1Application {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastConsumer1Application.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastConsumer1Application.class, args);
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer1 Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
```
#### Consumer2
**application.yml**
```yaml
server:
port: 28083
spring:
application:
name: rocketmq-broadcast-consumer2-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
consumer-in-0:
consumer:
messageModel: BROADCASTING
bindings:
consumer-in-0:
destination: broadcast
group: broadcast-consumer
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQBroadcastConsumer2Application {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastConsumer2Application.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastConsumer2Application.class, args);
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer2 Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
```
## Order example
RocketMQ provides ordered messages using FIFO order.
There are two types of ordered messages.
* Global: For a specified topic, all messages are published and consumed in strict FIFO (First In First Out) order.
* Partition: For a specified topic, all messages are partitioned according to the `Sharding Key`. Messages within the same partition are published and consumed in strict FIFO order. `Sharding Key` is a key field used to distinguish different partitions in sequential messages, and it is a completely different concept from the Key of ordinary messages.
### Create Topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t orderly
```
### Example code
**application.yml**
```yaml
server:
port: 28082
spring:
application:
name: rocketmq-orderly-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
# 定义messageSelector
messageQueueSelector: orderlyMessageQueueSelector
consumer-in-0:
consumer:
# tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } .
subscription: 'TagA || TagC || TagD'
push:
orderly: true
bindings:
producer-out-0:
destination: orderly
consumer-in-0:
destination: orderly
group: orderly-consumer
logging:
level:
org.springframework.context.support: debug
```
**MessageQueueSelector**
Choose a partition selection algorithm for you, and ensure that the same parameters get the same results.
```java
@Component
public class OrderlyMessageQueueSelector implements MessageQueueSelector {
private static final Logger log = LoggerFactory
.getLogger(OrderlyMessageQueueSelector.class);
@Override
public MessageQueue select(List mqs, Message msg, Object arg) {
Integer id = (Integer) ((MessageHeaders) arg).get(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID);
String tag = (String) ((MessageHeaders) arg).get(MessageConst.PROPERTY_TAGS);
int index = id % RocketMQOrderlyConsumeApplication.tags.length % mqs.size();
return mqs.get(index);
}
}
```
**Producer&Consumer**
```java
@SpringBootApplication
public class RocketMQOrderlyConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQOrderlyConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
/***
* tag array.
*/
public static final String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
public static void main(String[] args) {
SpringApplication.run(RocketMQOrderlyConsumeApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_TAGS, tags[i % tags.length]);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
String tagHeaderKey = RocketMQMessageConverterSupport.toRocketHeaderKey(
MessageConst.PROPERTY_TAGS).toString();
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " TAG:" +
msg.getHeaders().get(tagHeaderKey).toString());
try {
Thread.sleep(100);
}
catch (InterruptedException ignored) {
}
};
}
}
```
## Schedule example
Scheduled messages differ from normal messages in that they won’t be delivered until a provided time later.
### Create topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t delay
```
### Example code
**application.yml**
```yaml
server:
port: 28086
spring:
application:
name: rocketmq-delay-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
bindings:
producer-out-0:
destination: delay
consumer-in-0:
destination: delay
group: delay-group
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQDelayConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQDelayConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQDelayConsumeApplication.class, args);
}
@Bean
public ApplicationRunner producerDelay() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
// Set the delay level 1~10
headers.put(MessageConst.PROPERTY_DELAY_TIME_LEVEL, 2);
Message msg = new GenericMessage(new SimpleMsg("Delay RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
```
## Filter example
### Create topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t sql
```
### Example code
**application.yml**
RocketMQ stream binder supports filter by tag or sql, just setting `spring.cloud.stream.rocketmq.bindings..consumer.subscription`.
Tag example: `tag:red || blue`
Sql example: `sql:(color in ('red1', 'red2', 'red4') and price>3)`
More: [Filter](https://rocketmq.apache.org/docs/filter-by-sql92-example/)
```yaml
server:
port: 28087
spring:
application:
name: rocketmq-sql-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
consumer-in-0:
consumer:
# tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } .
subscription: sql:(color in ('red1', 'red2', 'red4') and price>3)
bindings:
producer-out-0:
destination: sql
consumer-in-0:
destination: sql
group: sql-group
logging:
level:
org.springframework.context.support: debug
```
**code**
```java
@SpringBootApplication
public class RocketMQSqlConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQSqlConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQSqlConsumeApplication.class, args);
}
/**
* color array.
*/
public static final String[] color = new String[] {"red1", "red2", "red3", "red4", "red5"};
/**
* price array.
*/
public static final Integer[] price = new Integer[] {1, 2, 3, 4, 5};
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put("color", color[i % color.length]);
headers.put("price", price[i % price.length]);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
String colorHeaderKey = "color";
String priceHeaderKey = "price";
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " COLOR:" +
msg.getHeaders().get(colorHeaderKey).toString() + " " +
"PRICE: " + msg.getHeaders().get(priceHeaderKey).toString());
};
}
}
```
#### 常见问题
- MQClientException: The broker does not support consumer to filter message by SQL92
1. Modify RocketMQ server configuration file.
In the `conf/2m-2s-async/broker-a.properties` configuration file, add `enablePropertyFilter=true`.
2. Restart mqbroker and specify the configuration file.
Specify the configuration file when `mqbroker` starts: `conf/2m-2s-async/broker-a.properties`, for example:
```shell
bin/mqbroker -n 127.0.0.1:9876 -c conf/2m-2s-async/broker-a.properties autoCreateTopicEnable=true
```
## Transaction example
### What is transactional message?
Refer to [Transaction Example](https://rocketmq.apache.org/docs/transaction-example/).
> It can be thought of as a two-phase commit message implementation to ensure eventual consistency in distributed system. Transactional message ensures that the execution of local transaction and the sending of message can be performed atomically.
### Application
> 1、 Transactional status
>
> There are three states for transactional message:
> (1) TransactionStatus.CommitTransaction: commit transaction,it means that allow consumers to consume this message.
> (2) TransactionStatus.RollbackTransaction: rollback transaction,it means that the message will be deleted and not allowed to consume.
> (3) TransactionStatus.Unknown: intermediate state,it means that MQ is needed to check back to determine the status.
### Create topic
```sh
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t tx
```
### Example code
**application.yml**
```yaml
server:
port: 28088
spring:
application:
name: rocketmq-tx-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
transactionListener: myTransactionListener
producerType: Trans
bindings:
producer-out-0:
destination: tx
consumer-in-0:
destination: tx
group: tx-group
logging:
level:
org.springframework.context.support: debug
```
**TransactionListenerImpl**
To execute local transaction.
```java
@Component("myTransactionListener")
public class TransactionListenerImpl implements TransactionListener {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Object num = msg.getProperty("test");
if ("1".equals(num)) {
System.out.println("executer: " + new String(msg.getBody()) + " unknown");
return LocalTransactionState.UNKNOW;
}
else if ("2".equals(num)) {
System.out.println("executer: " + new String(msg.getBody()) + " rollback");
return LocalTransactionState.ROLLBACK_MESSAGE;
}
System.out.println("executer: " + new String(msg.getBody()) + " commit");
return LocalTransactionState.COMMIT_MESSAGE;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
System.out.println("check: " + new String(msg.getBody()));
return LocalTransactionState.COMMIT_MESSAGE;
}
}
```
**producer and consumer**
```java
@SpringBootApplication
public class RocketMQTxApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQTxApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQTxApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 1; i <= 4; i++) {
MessageBuilder builder = MessageBuilder.withPayload(new SimpleMsg("Hello Tx msg " + i));
builder.setHeader("test", String.valueOf(i))
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
builder.setHeader(RocketMQConst.USER_TRANSACTIONAL_ARGS, "binder");
Message msg = builder.build();
streamBridge.send("producer-out-0", msg);
System.out.println("send Msg:" + msg.toString());
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
Object arg = msg.getHeaders();
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " ARG:"
+ arg.toString());
};
}
}
```
## Endpoint
Add dependency `spring-cloud-starter-stream-rocketmq` to your pom.xml file, and configure your endpoint security strategy.
* Spring Boot1.x: Add configuration `management.security.enabled=false`
* Spring Boot2.x: Add configuration `management.endpoints.web.exposure.include=*`
To view the endpoint information, visit the following URLS:
* Spring Boot1.x: Sentinel Endpoint URL is http://127.0.0.1:18083/rocketmq_binder.
* Spring Boot2.x: Sentinel Endpoint URL is http://127.0.0.1:18083/actuator/rocketmq-binder.
Endpoint will metrics some data like last send timestamp, sending or receive message successfully times or unsuccessfully times.
```json
{
"runtime": {
"lastSend.timestamp": 1542786623915
},
"metrics": {
"scs-rocketmq.consumer.test-topic.totalConsumed": {
"count": 11
},
"scs-rocketmq.consumer.test-topic.totalConsumedFailures": {
"count": 0
},
"scs-rocketmq.producer.test-topic.totalSentFailures": {
"count": 0
},
"scs-rocketmq.consumer.test-topic.consumedPerSecond": {
"count": 11,
"fifteenMinuteRate": 0.012163847780107841,
"fiveMinuteRate": 0.03614605351360527,
"meanRate": 0.3493213353657594,
"oneMinuteRate": 0.17099243039490175
},
"scs-rocketmq.producer.test-topic.totalSent": {
"count": 5
},
"scs-rocketmq.producer.test-topic.sentPerSecond": {
"count": 5,
"fifteenMinuteRate": 0.005540151995103271,
"fiveMinuteRate": 0.01652854617838251,
"meanRate": 0.10697493212602836,
"oneMinuteRate": 0.07995558537067671
},
"scs-rocketmq.producer.test-topic.sentFailuresPerSecond": {
"count": 0,
"fifteenMinuteRate": 0.0,
"fiveMinuteRate": 0.0,
"meanRate": 0.0,
"oneMinuteRate": 0.0
},
"scs-rocketmq.consumer.test-topic.consumedFailuresPerSecond": {
"count": 0,
"fifteenMinuteRate": 0.0,
"fiveMinuteRate": 0.0,
"meanRate": 0.0,
"oneMinuteRate": 0.0
}
}
}
```
Note: You should add [metrics-core dependency](https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core) if you want to see metrics data. endpoint will show warning information if you don't add that dependency:
```json
{
"warning": "please add metrics-core dependency, we use it for metrics"
}
```
## More
For more information about RocketMQ, see [RocketMQ Project](https://rocketmq.apache.org).
If you have any ideas or suggestions for Spring Cloud RocketMQ Binder, please don't hesitate to tell us by submitting github issues.
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer1-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../../pom.xml4.0.0rocketmq-broadcast-consumer1-exampleSpring Cloud Starter Stream Alibaba RocketMQ Broadcasting Consume Example Cosumer1Example demonstrating how to broadcast consumptionjarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jsoncom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer1-example/src/main/java/com/alibaba/cloud/examples/broadcast/RocketMQBroadcastConsumer1Application.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.broadcast;
import java.util.function.Consumer;
import com.alibaba.cloud.examples.common.SimpleMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQBroadcastConsumer1Application {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastConsumer1Application.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastConsumer1Application.class, args);
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer1 Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer1-example/src/main/resources/application.yml
================================================
server:
port: 28084
spring:
application:
name: rocketmq-broadcast-consumer1-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
consumer-in-0:
consumer:
messageModel: BROADCASTING
bindings:
consumer-in-0:
destination: broadcast
group: broadcast-consumer
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer2-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../../pom.xml4.0.0rocketmq-broadcast-consumer2-exampleSpring Cloud Starter Stream Alibaba RocketMQ Broadcasting Consume Example Consumer2Example demonstrating how to broadcast consumptionjarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jsoncom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer2-example/src/main/java/com/alibaba/cloud/examples/broadcast/RocketMQBroadcastConsumer2Application.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.broadcast;
import java.util.function.Consumer;
import com.alibaba.cloud.examples.common.SimpleMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQBroadcastConsumer2Application {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastConsumer2Application.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastConsumer2Application.class, args);
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer2 Receive New Messages: " + msg.getPayload().getMsg());
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-consumer2-example/src/main/resources/application.yml
================================================
server:
port: 28083
spring:
application:
name: rocketmq-broadcast-consumer2-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
consumer-in-0:
consumer:
messageModel: BROADCASTING
bindings:
consumer-in-0:
destination: broadcast
group: broadcast-consumer
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-producer-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../../pom.xml4.0.0rocketmq-broadcast-producer-exampleSpring Cloud Starter Stream Alibaba RocketMQ Broadcasting Consume Example ProducerExample demonstrating how to use rocketmq to producejarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jsoncom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-producer-example/src/main/java/com/alibaba/cloud/examples/broadcast/RocketMQBroadcastProducerApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.broadcast;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.cloud.examples.common.SimpleMsg;
import org.apache.rocketmq.common.message.MessageConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQBroadcastProducerApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQBroadcastProducerApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQBroadcastProducerApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-broadcast-example/rocketmq-broadcast-producer-example/src/main/resources/application.yml
================================================
server:
port: 28085
spring:
application:
name: rocketmq-broadcast-producer-example
cloud:
stream:
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
bindings:
producer-out-0:
destination: broadcast
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-comprehensive-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0rocketmq-comprehensive-exampleSpring Cloud Starter Stream Alibaba RocketMQ Comprehensive ExampleExample demonstrating how to use rocketmq to produce, process and consumejarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jsonorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-comprehensive-example/src/main/java/com/alibaba/cloud/examples/RocketMQComprehensiveApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.time.Duration;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.support.StringObjectMapBuilder;
/**
* @author freeman
*/
@SpringBootApplication
public class RocketMQComprehensiveApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQComprehensiveApplication.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQComprehensiveApplication.class, args);
}
@Bean
public Supplier> producer() {
return () -> Flux.interval(Duration.ofSeconds(2)).map(id -> {
User user = new User();
user.setId(id.toString());
user.setName("freeman");
user.setMeta(new StringObjectMapBuilder()
.put("hobbies", Arrays.asList("movies", "songs")).put("age", 21)
.get());
return user;
}).log();
}
@Bean
public Function, Flux> processor() {
return flux -> flux.map(user -> {
user.setId(String.valueOf(
Long.parseLong(user.getId()) * Long.parseLong(user.getId())));
user.setName("not freeman");
user.getMeta().put("hobbies", Arrays.asList("programming"));
return user;
});
}
@Bean
public Consumer consumer() {
return num -> log.info(num.toString());
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-comprehensive-example/src/main/java/com/alibaba/cloud/examples/User.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.Map;
/**
* @author freeman
*/
public class User {
private String id;
private String name;
private Map meta;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map getMeta() {
return meta;
}
public void setMeta(Map meta) {
this.meta = meta;
}
@Override
public String toString() {
return "User{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", meta=" + meta
+ '}';
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-comprehensive-example/src/main/resources/application.yml
================================================
server:
port: 28082
spring:
application:
name: rocketmq-comprehensive-example
cloud:
function:
definition: producer;consumer;processor
stream:
rocketmq:
binder:
name-server: 127.0.0.1:9876
bindings:
# TODO producer must have a group, need optimization !!!
producer-out-0:
producer:
group: output_1
processor-out-0:
producer:
group: output_2
bindings:
producer-out-0:
destination: num
processor-out-0:
destination: square
processor-in-0:
destination: num
group: processor_group
consumer-in-0:
destination: square
group: consumer_group
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-delay-consume-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0rocketmq-delay-consume-exampleSpring Cloud Starter Stream Alibaba RocketMQ Delay Consume ExampleExample demonstrating how to use rocketmq to delay consumejarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatorcom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-delay-consume-example/src/main/java/com/alibaba/cloud/examples/delay/RocketMQDelayConsumeApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.delay;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import com.alibaba.cloud.examples.common.SimpleMsg;
import org.apache.rocketmq.common.message.MessageConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQDelayConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQDelayConsumeApplication.class);
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
private static LocalDateTime sendTime;
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQDelayConsumeApplication.class, args);
}
/**
* Produce delay messages.
*/
@Bean
public ApplicationRunner producerDelay() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
headers.put(MessageConst.PROPERTY_DELAY_TIME_LEVEL, 2);
Message msg = new GenericMessage(new SimpleMsg("Delay RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
sendTime = LocalDateTime.now();
log.info("All 100 messages sent at {}", sendTime.format(FORMATTER));
};
}
@Bean
public Consumer> consumer() {
return msg -> {
log.info(Thread.currentThread().getName() + " Consumer Receive New Messages: " + msg.getPayload().getMsg() + ". Delay time(s): " + (LocalDateTime.now().getSecond() - sendTime.getSecond()));
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-delay-consume-example/src/main/resources/application.yml
================================================
server:
port: 28086
spring:
application:
name: rocketmq-delay-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
bindings:
producer-out-0:
destination: delay
consumer-in-0:
destination: delay
group: delay-group
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-example-common/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0rocketmq-example-commonSpring Cloud Starter Stream Alibaba RocketMQ Example COMMONSome rocketMQ exmaple common codesjar
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-example-common/src/main/java/com/alibaba/cloud/examples/common/SimpleMsg.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.common;
/**
* @author sorie
*/
public class SimpleMsg {
private String msg;
public SimpleMsg() {
}
public SimpleMsg(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-example-common/src/main/resources/application.yml
================================================
server:
port: 28087
spring:
application:
name: rocketmq-sql-consume-example
cloud:
stream:
function:
definition: producer;consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
consumer-in-0:
consumer:
# tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } .
subscription: sql:(color in ('red1', 'red2', 'red4') and price>3)
bindings:
producer-out-0:
destination: sql
consumer-in-0:
destination: sql
group: sql-group
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-orderly-consume-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0rocketmq-orderly-consume-exampleSpring Cloud Starter Stream Alibaba RocketMQ Orderly Consume ExampleExample demonstrating how to use rocketmq to produce, and consume orderlyjarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jsoncom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-orderly-consume-example/src/main/java/com/alibaba/cloud/examples/orderly/OrderlyMessageQueueSelector.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.orderly;
import java.util.List;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.common.message.MessageQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;
/**
* @author sorie
*/
@Component
public class OrderlyMessageQueueSelector implements MessageQueueSelector {
private static final Logger log = LoggerFactory
.getLogger(OrderlyMessageQueueSelector.class);
/**
* to select a fixed queue by id.
* @param mqs all message queues of this topic.
* @param msg mq message.
* @param arg mq arguments.
* @return message queue selected.
*/
@Override
public MessageQueue select(List mqs, Message msg, Object arg) {
Integer id = (Integer) ((MessageHeaders) arg).get(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID);
int index = id % RocketMQOrderlyConsumeApplication.tags.length % mqs.size();
return mqs.get(index);
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-orderly-consume-example/src/main/java/com/alibaba/cloud/examples/orderly/RocketMQOrderlyConsumeApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.orderly;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import com.alibaba.cloud.examples.common.SimpleMsg;
import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQMessageConverterSupport;
import org.apache.rocketmq.common.message.MessageConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQOrderlyConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQOrderlyConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
/***
* tag array.
*/
public static final String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
public static void main(String[] args) {
SpringApplication.run(RocketMQOrderlyConsumeApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put(MessageConst.PROPERTY_TAGS, tags[i % tags.length]);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
String tagHeaderKey = RocketMQMessageConverterSupport.toRocketHeaderKey(
MessageConst.PROPERTY_TAGS).toString();
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " TAG:" +
msg.getHeaders().get(tagHeaderKey).toString());
try {
Thread.sleep(100);
}
catch (InterruptedException ignored) {
}
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-orderly-consume-example/src/main/resources/application.yml
================================================
server:
port: 28082
spring:
application:
name: rocketmq-orderly-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
messageQueueSelector: orderlyMessageQueueSelector
consumer-in-0:
consumer:
# tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } .
subscription: 'TagA || TagC || TagD'
push:
orderly: true
bindings:
producer-out-0:
destination: orderly
consumer-in-0:
destination: orderly
group: orderly-consumer
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-pollable-consume-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0rocketmq-pollable-consume-exampleSpring Cloud Starter Stream Alibaba RocketMQ PollableMessageSource Consume ExampleExample demonstrating how to use rocketmq to produce, and consume by PollableMessageSourcejarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jsoncom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-pollable-consume-example/src/main/java/com/alibaba/cloud/examples/pollable/RocketMQPollableConsumeApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.pollable;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.cloud.examples.common.SimpleMsg;
import org.apache.rocketmq.common.message.MessageConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.binder.PollableMessageSource;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQPollableConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQPollableConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(RocketMQPollableConsumeApplication.class, args);
PollableMessageSource destIn = context.getBean(PollableMessageSource.class);
new Thread(() -> {
while (true) {
try {
if (!destIn.poll((m) -> {
SimpleMsg newPayload = (SimpleMsg) m.getPayload();
System.out.println(newPayload.getMsg());
}, new ParameterizedTypeReference() {
})) {
Thread.sleep(1000);
}
}
catch (Exception e) {
// handle failure
}
}
}).start();
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
Message msg = new GenericMessage(
new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-pollable-consume-example/src/main/resources/application.yml
================================================
server:
port: 28089
spring:
application:
name: rocketmq-pollable-consume-example
cloud:
stream:
pollable-source: pollable
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
bindings:
producer-out-0:
destination: pollable
pollable-in-0:
destination: pollable
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-sql-consume-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0rocketmq-sql-consume-exampleSpring Cloud Starter Stream Alibaba RocketMQ Sql Consume ExampleExample demonstrating how to use rocketmq to filter message by sqljarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatorcom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-sql-consume-example/src/main/java/com/alibaba/cloud/examples/sql/RocketMQSqlConsumeApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.sql;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import com.alibaba.cloud.examples.common.SimpleMsg;
import org.apache.rocketmq.common.message.MessageConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQSqlConsumeApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQSqlConsumeApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQSqlConsumeApplication.class, args);
}
/**
* color array.
*/
public static final String[] color = new String[] {"red1", "red2", "red3", "red4", "red5"};
/**
* price array.
*/
public static final Integer[] price = new Integer[] {1, 2, 3, 4, 5};
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 0; i < 100; i++) {
String key = "KEY" + i;
Map headers = new HashMap<>();
headers.put(MessageConst.PROPERTY_KEYS, key);
headers.put("color", color[i % color.length]);
headers.put("price", price[i % price.length]);
headers.put(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID, i);
Message msg = new GenericMessage(new SimpleMsg("Hello RocketMQ " + i), headers);
streamBridge.send("producer-out-0", msg);
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
String colorHeaderKey = "color";
String priceHeaderKey = "price";
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " COLOR:" +
msg.getHeaders().get(colorHeaderKey).toString() + " " +
"PRICE: " + msg.getHeaders().get(priceHeaderKey).toString());
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-sql-consume-example/src/main/resources/application.yml
================================================
server:
port: 28087
spring:
application:
name: rocketmq-sql-consume-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
consumer-in-0:
consumer:
# tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } .
subscription: sql:(color in ('red1', 'red2', 'red4') and price>3)
bindings:
producer-out-0:
destination: sql
consumer-in-0:
destination: sql
group: sql-group
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-tx-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0rocketmq-tx-exampleSpring Cloud Starter Stream Alibaba RocketMQ Transaction message ExampleExample demonstrating how to send and consume transaction messages in rocketmqjarcom.alibaba.cloudspring-cloud-starter-stream-rocketmqorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatorcom.alibaba.cloudrocketmq-example-common${revision}org.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-tx-example/src/main/java/com/alibaba/cloud/examples/tx/RocketMQTxApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.tx;
import java.util.function.Consumer;
import com.alibaba.cloud.examples.common.SimpleMsg;
import com.alibaba.cloud.stream.binder.rocketmq.constant.RocketMQConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.MimeTypeUtils;
/**
* @author sorie
*/
@SpringBootApplication
public class RocketMQTxApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQTxApplication.class);
@Autowired
private StreamBridge streamBridge;
public static void main(String[] args) {
SpringApplication.run(RocketMQTxApplication.class, args);
}
@Bean
public ApplicationRunner producer() {
return args -> {
for (int i = 1; i <= 4; i++) {
MessageBuilder builder = MessageBuilder.withPayload(new SimpleMsg("Hello Tx msg " + i));
builder.setHeader("test", String.valueOf(i))
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
builder.setHeader(RocketMQConst.USER_TRANSACTIONAL_ARGS, "binder");
Message msg = builder.build();
streamBridge.send("producer-out-0", msg);
System.out.println("send Msg:" + msg.toString());
}
};
}
@Bean
public Consumer> consumer() {
return msg -> {
Object arg = msg.getHeaders();
log.info(Thread.currentThread().getName() + " Receive New Messages: " + msg.getPayload().getMsg() + " ARG:"
+ arg.toString());
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-tx-example/src/main/java/com/alibaba/cloud/examples/tx/TransactionListenerImpl.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.tx;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;
/**
* @author Jim
*/
@Component("myTransactionListener")
public class TransactionListenerImpl implements TransactionListener {
/**
* Execute local transaction.
* @param msg messages
* @param arg message args
* @return Transaction state
*/
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Object num = msg.getProperty("test");
if ("1".equals(num)) {
System.out.println("executer: " + new String(msg.getBody()) + " unknown");
return LocalTransactionState.UNKNOW;
}
else if ("2".equals(num)) {
System.out.println("executer: " + new String(msg.getBody()) + " rollback");
return LocalTransactionState.ROLLBACK_MESSAGE;
}
System.out.println("executer: " + new String(msg.getBody()) + " commit");
return LocalTransactionState.COMMIT_MESSAGE;
}
/**
* MQ check back local transaction states.
* @param msg messages
* @return Transaction state
*/
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
System.out.println("check: " + new String(msg.getBody()));
return LocalTransactionState.COMMIT_MESSAGE;
}
}
================================================
FILE: spring-cloud-alibaba-examples/rocketmq-example/rocketmq-tx-example/src/main/resources/application.yml
================================================
server:
port: 28088
spring:
application:
name: rocketmq-tx-example
cloud:
stream:
function:
definition: consumer;
rocketmq:
binder:
name-server: localhost:9876
bindings:
producer-out-0:
producer:
group: output_1
transactionListener: myTransactionListener
producerType: Trans
bindings:
producer-out-0:
destination: tx
consumer-in-0:
destination: tx
group: tx-group
logging:
level:
org.springframework.context.support: debug
================================================
FILE: spring-cloud-alibaba-examples/seata-example/account-service/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0account-serviceSpring Cloud Starter Alibaba Seata Example - Account Servicejarcom.alibaba.cloudspring-cloud-starter-alibaba-seatacom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jorg.apache.logging.log4jlog4j-coreorg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/seata-example/account-service/src/main/java/com/alibaba/cloud/examples/AccountApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author xiaojing
*/
@SpringBootApplication
public class AccountApplication {
public static void main(String[] args) {
SpringApplication.run(AccountApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/account-service/src/main/java/com/alibaba/cloud/examples/AccountController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.Random;
import org.apache.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xiaojing
*/
@RestController
public class AccountController {
private static final Logger LOGGER = LoggerFactory.getLogger(AccountController.class);
private static final String SUCCESS = "SUCCESS";
private static final String FAIL = "FAIL";
private final JdbcTemplate jdbcTemplate;
private Random random;
public AccountController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.random = new Random();
}
@PostMapping(value = "/account", produces = "application/json")
public String account(String userId, int money) {
LOGGER.info("Account Service ... xid: " + RootContext.getXID());
if (random.nextBoolean()) {
throw new RuntimeException("this is a mock Exception");
}
int result = jdbcTemplate.update(
"update account_tbl set money = money - ? where user_id = ?",
new Object[] { money, userId });
LOGGER.info("Account Service End ... ");
if (result == 1) {
return SUCCESS;
}
return FAIL;
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/account-service/src/main/java/com/alibaba/cloud/examples/DatabaseConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author xiaojing
*/
@Configuration
public class DatabaseConfiguration {
// druid don't support GraalVM now because of there is CGlib proxy
// @Bean
// @Primary
// @ConfigurationProperties("spring.datasource")
// public DataSource storageDataSource() {
// return new DruidDataSource();
// }
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("delete from account_tbl where user_id = 'U100001'");
jdbcTemplate.update(
"insert into account_tbl(user_id, money) values ('U100001', 10000)");
return jdbcTemplate;
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/account-service/src/main/resources/application.yml
================================================
base:
config:
mdb:
hostname: 127.0.0.1 #your mysql server ip address
dbname: seata #your database name for test
port: 3306 #your mysql server listening port
username: 'root' #your mysql server username
password: 'root' #your mysql server password
server:
port: 18084
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
application:
name: account-service
main:
allow-bean-definition-overriding: true
datasource:
name: storageDataSource
# druid don't support GraalVM now because of there is CGlib proxy
# type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${base.config.mdb.hostname}:${base.config.mdb.port}/${base.config.mdb.dbname}?useSSL=false&serverTimezone=UTC
username: ${base.config.mdb.username}
password: ${base.config.mdb.password}
# druid:
# max-active: 20
# min-idle: 2
# initial-size: 2
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-tx-group
config:
type: nacos
nacos:
serverAddr: 127.0.0.1:8848
dataId: "seata.properties"
group: SEATA_GROUP
username: 'nacos'
password: 'nacos'
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
cluster: default
group: SEATA_GROUP
username: 'nacos'
password: 'nacos'
================================================
FILE: spring-cloud-alibaba-examples/seata-example/all.sql
================================================
-- -------------------------------- Create undo_ Log table --------------------------------
-- Seata AT Mode Need to use undo_ Log table.
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;
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid_and_branch_id` (`xid` , `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
primary key (`lock_key`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
-- -------------- Create the database tables needed by the business in the example ----------------
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
================================================
FILE: spring-cloud-alibaba-examples/seata-example/business-service/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0business-serviceSpring Cloud Starter Alibaba Seata Example - Business Servicejarcom.alibaba.cloudspring-cloud-starter-alibaba-seatacom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-openfeignorg.springframework.cloudspring-cloud-starter-loadbalancerorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframeworkspring-txorg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/seata-example/business-service/src/main/java/com/alibaba/cloud/examples/BusinessApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaojing
*/
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient(autoRegister = false)
@LoadBalancerClients({
@LoadBalancerClient("storage-service"),
@LoadBalancerClient("order-service"),
@LoadBalancerClient("service-provider")
})
public class BusinessApplication {
public static void main(String[] args) {
SpringApplication.run(BusinessApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@FeignClient("storage-service")
public interface StorageService {
@GetMapping(path = "/storage/{commodityCode}/{count}")
String storage(@PathVariable("commodityCode") String commodityCode,
@PathVariable("count") int count);
}
@FeignClient("order-service")
public interface OrderService {
@PostMapping(path = "/order")
String order(@RequestParam("userId") String userId,
@RequestParam("commodityCode") String commodityCode,
@RequestParam("orderCount") int orderCount);
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/business-service/src/main/java/com/alibaba/cloud/examples/HomeController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import com.alibaba.cloud.examples.BusinessApplication.OrderService;
import com.alibaba.cloud.examples.BusinessApplication.StorageService;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaojing
*/
@RestController
public class HomeController {
private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);
private static final String SUCCESS = "SUCCESS";
private static final String FAIL = "FAIL";
private static final String USER_ID = "U100001";
private static final String COMMODITY_CODE = "C00321";
private static final int ORDER_COUNT = 2;
private final RestTemplate restTemplate;
private final OrderService orderService;
private final StorageService storageService;
public HomeController(RestTemplate restTemplate, OrderService orderService,
StorageService storageService) {
this.restTemplate = restTemplate;
this.orderService = orderService;
this.storageService = storageService;
}
@GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx")
@GetMapping(value = "/seata/rest", produces = "application/json")
public String rest() {
String result = restTemplate.getForObject(
"http://127.0.0.1:18082/storage/" + COMMODITY_CODE + "/" + ORDER_COUNT,
String.class);
if (!SUCCESS.equals(result)) {
throw new RuntimeException();
}
String url = "http://127.0.0.1:18083/order";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap map = new LinkedMultiValueMap();
map.add("userId", USER_ID);
map.add("commodityCode", COMMODITY_CODE);
map.add("orderCount", ORDER_COUNT + "");
HttpEntity> request = new HttpEntity>(
map, headers);
ResponseEntity response;
try {
response = restTemplate.postForEntity(url, request, String.class);
}
catch (Exception exx) {
throw new RuntimeException("mock error");
}
result = response.getBody();
if (!SUCCESS.equals(result)) {
throw new RuntimeException();
}
return SUCCESS;
}
@GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx")
@GetMapping(value = "/seata/feign", produces = "application/json")
public String feign() {
String result = storageService.storage(COMMODITY_CODE, ORDER_COUNT);
if (!SUCCESS.equals(result)) {
throw new RuntimeException();
}
result = orderService.order(USER_ID, COMMODITY_CODE, ORDER_COUNT);
if (!SUCCESS.equals(result)) {
throw new RuntimeException();
}
return SUCCESS;
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/business-service/src/main/java/com/alibaba/cloud/examples/Order.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.io.Serializable;
public class Order implements Serializable {
/**
* order id.
*/
public long id;
/**
* user id.
*/
public String userId;
/**
* commodity code.
*/
public String commodityCode;
/**
* count.
*/
public int count;
/**
* money.
*/
public int money;
@Override
public String toString() {
return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ commodityCode + '\'' + ", count=" + count + ", money=" + money + '}';
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/business-service/src/main/resources/application.yml
================================================
server:
port: 18081
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
loadbalancer:
ribbon:
enabled:true
application:
name: business-service
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-tx-group
config:
type: nacos
nacos:
serverAddr: 127.0.0.1:8848
dataId: "seata.properties"
group: SEATA_GROUP
username: 'nacos'
password: 'nacos'
registry:
type: nacos
nacos:
cluster: default
group: SEATA_GROUP
application: seata-server
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
feign:
client:
config:
default:
connectTimeout: 10000
readTimeout: 10000
logging:
level:
io:
seata: debug
================================================
FILE: spring-cloud-alibaba-examples/seata-example/order-service/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0order-serviceSpring Cloud Starter Alibaba Seata Example - Order Servicejarcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-seataorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jorg.apache.logging.log4jlog4j-coreorg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/seata-example/order-service/src/main/java/com/alibaba/cloud/examples/DatabaseConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author xiaojing
*/
@Configuration
public class DatabaseConfiguration {
// druid don't support GraalVM now because of there is CGlib proxy
// @Bean
// @Primary
// @ConfigurationProperties("spring.datasource")
// public DataSource storageDataSource() {
// return new DruidDataSource();
// }
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute("TRUNCATE TABLE order_tbl");
return jdbcTemplate;
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/order-service/src/main/java/com/alibaba/cloud/examples/Order.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.io.Serializable;
public class Order implements Serializable {
/**
* id.
*/
public long id;
/**
* user id.
*/
public String userId;
/**
* commodity code.
*/
public String commodityCode;
/**
* count.
*/
public int count;
/**
* money.
*/
public int money;
@Override
public String toString() {
return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ commodityCode + '\'' + ", count=" + count + ", money=" + money + '}';
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/order-service/src/main/java/com/alibaba/cloud/examples/OrderApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaojing
*/
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/order-service/src/main/java/com/alibaba/cloud/examples/OrderController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;
import org.apache.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaojing
*/
@RestController
public class OrderController {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderController.class);
private static final String SUCCESS = "SUCCESS";
private static final String FAIL = "FAIL";
private static final String USER_ID = "U100001";
private static final String COMMODITY_CODE = "C00321";
private final JdbcTemplate jdbcTemplate;
private final RestTemplate restTemplate;
private Random random;
public OrderController(JdbcTemplate jdbcTemplate, RestTemplate restTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.restTemplate = restTemplate;
this.random = new Random();
}
@PostMapping(value = "/order", produces = "application/json")
public String order(String userId, String commodityCode, int orderCount) {
LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID());
int orderMoney = calculate(commodityCode, orderCount);
invokerAccountService(orderMoney);
final Order order = new Order();
order.userId = userId;
order.commodityCode = commodityCode;
order.count = orderCount;
order.money = orderMoney;
KeyHolder keyHolder = new GeneratedKeyHolder();
int result = jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException {
PreparedStatement pst = con.prepareStatement(
"insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)",
PreparedStatement.RETURN_GENERATED_KEYS);
pst.setObject(1, order.userId);
pst.setObject(2, order.commodityCode);
pst.setObject(3, order.count);
pst.setObject(4, order.money);
return pst;
}
}, keyHolder);
order.id = keyHolder.getKey().longValue();
if (random.nextBoolean()) {
throw new RuntimeException("this is a mock Exception");
}
LOGGER.info("Order Service End ... Created " + order);
if (result == 1) {
return SUCCESS;
}
return FAIL;
}
private int calculate(String commodityId, int orderCount) {
return 2 * orderCount;
}
private void invokerAccountService(int orderMoney) {
String url = "http://127.0.0.1:18084/account";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap map = new LinkedMultiValueMap();
map.add("userId", USER_ID);
map.add("money", orderMoney + "");
HttpEntity> request = new HttpEntity>(
map, headers);
ResponseEntity response = restTemplate.postForEntity(url, request,
String.class);
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/order-service/src/main/resources/application.yml
================================================
base:
config:
mdb:
hostname: 127.0.0.1 #your mysql server ip address
dbname: seata #your database name for test
port: 3306 #your mysql server listening port
username: 'root' #your mysql server username
password: 'root' #your mysql server password
server:
port: 18083
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
application:
name: order-service
main:
allow-bean-definition-overriding: true
datasource:
name: storageDataSource
# druid don't support GraalVM now because of there is CGlib proxy
# type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${base.config.mdb.hostname}:${base.config.mdb.port}/${base.config.mdb.dbname}?useSSL=false&serverTimezone=UTC
username: ${base.config.mdb.username}
password: ${base.config.mdb.password}
# druid:
# max-active: 20
# min-idle: 2
# initial-size: 2
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-tx-group
config:
type: nacos
nacos:
serverAddr: 127.0.0.1:8848
dataId: "seata.properties"
group: SEATA_GROUP
username: 'nacos'
password: 'nacos'
registry:
type: nacos
nacos:
cluster: default
group: SEATA_GROUP
application: seata-server
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
================================================
FILE: spring-cloud-alibaba-examples/seata-example/readme-zh.md
================================================
# Seata Example
## 项目说明
本项目演示如何使用 Seata Starter 完成 Spring Cloud Alibaba 应用的分布式事务接入。
[Seata](https://github.com/seata/seata) 是阿里巴巴开源的分布式事务中间件,以高效并且对业务 0 侵入的方式,解决微服务场景下面临的分布式事务问题。
## 准备工作
在运行此示例之前,需要完成以下几步准备工作:
### 1. 配置数据库
> **注意**: 实际上,Seata 支持不同的应用使用完全不相干的数据库,但是这里为了简单地演示 Seata 如何在 Spring Cloud 应用中使用,所以选择了 Mysql 数据库。
将 `account-server`、`order-service`、`storage-service` 这三个应用中 resources 目录下的 `application.yml` 文件中的以下配置修改成本地环境中的数据库配置。
```
base:
config:
mdb:
hostname: your mysql server ip address
dbname: your database name for test
port: your mysql server listening port
username: your mysql server username
password: your mysql server password
```
#### 创建 undo_log 表
Seata AT 模式 需要使用到 undo_log 表。
```sql
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
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;
```
#### 导入 seata-server db 模式所需要的数据库表
在数据库中初始化[global_table、branch_table、lock_table、distributed_lock](https://github.com/seata/seata/blob/2.1.0/script/server/db/mysql.sql)
```sql
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid_and_branch_id` (`xid` , `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
primary key (`lock_key`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
```
#### 创建应用示例中业务所需要的数据库表
```sql
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
### 2. 配置 Nacos
> Spring Cloud Alibaba 适配了 Nacos 3.1.0 版本,在本示例中,使用 Nacos 3.1.0 作为 Seata 的配置中心组件。
创建 Seata 的 Nacos 配置: data-id: `seata.properties` , Group: `SEATA_GROUP` (seata 2.x 默认分组) ,导入 [Seata Config](https://github.com/seata/seata/blob/2.1.0/script/config-center/config.txt)
在 `seata.properties` 配置文件中增加应用示例中需要的以下配置项:[事务群组配置](https://seata.io/zh-cn/docs/user/configurations.html)
```properties
service.vgroupMapping.default_tx_group=default # 用于指定全局事务组和本地事务组之间的映射关系
service.vgroupMapping.order-service-tx-group=default
service.vgroupMapping.account-service-tx-group=default
service.vgroupMapping.business-service-tx-group=default
service.vgroupMapping.storage-service-tx-group=default
```
### 3. 启动 Seata-server
> Seata 1.5.1 开始支持控制台 本地访问控制台地址:http://127.0.0.1:7091,通过 Seata 内置的控制台可以观察正在执行的事务信息和全局锁信息,事务执行结束即删除相关信息。
#### 1. 下载
点击下载( [Seata 2.5.0](https://github.com/apache/incubator-seata/releases/tag/v2.5.0)) 版本。 # github链接为源码包,需要使用 Maven 进行编译构建源码并生成 Seata 服务器 JAR 文件
或点击下载( [Apache-seata-2.5.0-incubating-bin.tar.gz](https://seata.apache.org/zh-cn/download/seata-server)) #二进制包,方便配备seata-server进行调试
#### 2. 配置 Seata-server
修改 `seata-server\conf\application.yml` 配置文件中的以下配置项:
- 注释 `group: SEATA_GROUP`
- 添加 Nacos 用户名和密码
```yml
seata:
# nacos配置
config:
type: nacos
nacos:
server-addr: # Nacos 服务地址
# group: SEATA_GROUP
# namespace: public # Nacos 命名空间(确保设置为实际值)
username: nacos
password: nacos
data-id: seata.properties # Nacos 中的配置文件名
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
registry:
# support: nacos 、 eureka 、 redis 、 zk 、 consul 、 etcd3 、 sofa 、 seata
type: nacos # 使用 Nacos 作为注册中心
nacos:
application: seata-server
# group: SEATA_GROUP
# namespace: public # Nacos 命名空间(确保设置为实际值)
cluster: default
server-addr: # Nacos 注册中心地址
username: nacos
password: nacos
```
- 添加 store 及 server 设置(示例-非必要)
```yml
store:
# 支持:file、db、redis、raft
mode: db # 使用数据库模式
session:
mode: file
lock:
mode: file
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true # MySQL 数据库连接
user: root # MySQL 用户名
password: rootpass # MySQL 密码
min-conn: 10
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
vgroup-table: vgroup_table
query-limit: 1000
max-wait: 5000
server:
service-port: 8091 # 配置服务端口
max-commit-retry-timeout: -1
max-rollback-retry-timeout: -1
rollback-failed-unlock-enable: false
enable-check-auth: true
enable-parallel-request-handle: true
enable-parallel-handle-branch: false
retry-dead-threshold: 70000
xaer-nota-retry-timeout: 60000
enableParallelRequestHandle: true
applicationDataLimitCheck: true
applicationDataLimit: 64000
recovery:
committing-retry-period: 1000
async-committing-retry-period: 1000
rollbacking-retry-period: 1000
end-status-retry-period: 1000
timeout-retry-period: 1000
undo:
log-save-days: 7
log-delete-period: 86400000
session:
branch-async-queue-size: 5000 # 异步分支队列大小
enable-branch-async-remove: false # 启用分支异步移除
ratelimit:
enable: false
bucketTokenNumPerSecond: 999999
bucketTokenMaxNum: 999999
bucketTokenInitialNum: 999999
metrics:
enabled: false
registry-type: compact
exporter-list: prometheus
exporter-prometheus-port: 9898
transport:
rpc-tc-request-timeout: 15000
enable-tc-server-batch-send-response: false
min-http-pool-size: 10
max-http-pool-size: 100
max-http-task-queue-size: 1000
http-pool-keep-alive-time: 500
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
boss-thread-size: 1
```
> **注意:**
> Nacos 3.1.0 开启鉴权,需要配置 `username` 和 `password` 属性,否则登陆失败。更多 Nacos 3.1.0 版本相关配置,参考 `nacos-example`。
> **Seata-server 启动时的 Nacos 服务注册分组需要和示例应用中的分组保持一致,否则出现无法找到 seata-server 的错误!**
> 更多 Seata-server 以 Nacos 作为配置中心的配置请参考:https://seata.io/zh-cn/docs/ops/deploy-by-docker-compose/#nacos-db
### 3. 启动 Seata-server
Windows:
```cmd
./seata-server.bat
```
Linux/Mac
```shell
sh seata-server.sh
```
更多配置启动参数请参考:https://seata.io/zh-cn/docs/user/quickstart/#%E6%AD%A5%E9%AA%A4-4-%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1
**注意** 如果你修改了 endpoint 且注册中心使用默认 file 类型,那么记得需要在各个示例工程中的 `file.conf` 文件中,修改 grouplist 的值(当 registry.conf 中 registry.type 或 config.type 为 file 时会读取内部的 file 节点中的文件名,若 type 不为 file 将直接从配置类型的对应元数据的注册配置中心读取数据),推荐大家使用 nacos 作为配置注册中心。
## 运行示例
分别运行 `account-server`、`order-service`、`storage-service` 和 `business-service` 这三个应用的 Main 函数,启动示例。
启动示例后,通过 HTTP 的 GET 方法访问如下 URL,可以分别验证在 `business-service` 中 通过 RestTemplate 和 FeignClient 调用其他服务的场景。
```shell
http://127.0.0.1:18081/seata/feign
http://127.0.0.1:18081/seata/rest
```
调用服务接口时,可能出现两种返回
1. SUCCESS:调用接口服务成功;
2. 500 异常,business-service mock 异常。
## 如何验证分布式事务成功?
### Xid 信息是否成功传递
在 `account-server`、`order-service` 和 `storage-service` 三个 服务的 Controller 中,第一个执行的逻辑都是输出 RootContext 中的 Xid 信息,如果看到都输出了正确的 Xid 信息,即每次都发生变化,且同一次调用中所有服务的 Xid 都一致。则表明 Seata 的 Xid 的传递和还原是正常的。
```bash
# 分别查看服务运行日志(示例)
Account Service ... xid: 192.168.44.1:8091:4540309594179612673
Order Service Begin ... xid: 192.168.44.1:8091:4540309594179612673
Storage Service Begin ... xid: 192.168.44.1:8091:4540309594179612673
...
Begin new global transaction [192.168.44.1:8091:4540309594179612673]
```
### 数据库中数据是否一致
在本示例中,我们模拟了一个用户购买货物的场景,StorageService 负责扣减库存数量,OrderService 负责保存订单,AccountService 负责扣减用户账户余额。
为了演示样例,我们在 OrderService 和 AccountService 中 使用 Random.nextBoolean() 的方式来随机抛出异常,模拟了在服务调用时随机发生异常的场景。
如果分布式事务生效的话, 那么以下等式应该成立
- 用户原始金额(1000) = 用户现存的金额 + 货物单价 (2) * 订单数量 * 每单的货物数量(2)
- 货物的初始数量(100) = 货物的现存数量 + 订单数量 * 每单的货物数量(2)
```sql
# 验证示例
SELECT * FROM account_tbl;
SELECT * FROM storage_tbl;
SELECT * FROM order_tbl;
```
注:由于使用了 Random.nextBoolean() 来随机抛出异常,模拟事务的异常情况,也需要验证分布式事务是否能正确回滚:
如果在 OrderService 和 AccountService 中抛出异常,StorageService 应该会回滚库存扣减,账户余额也应恢复到初始状态。
查看分布式事务日志:查看 undo_log 表和 global_table 表,确保在事务回滚时,相关记录被删除或恢复。
## 对 Spring Cloud 支持点
- 通过 Spring MVC 提供服务的服务提供者,在收到 header 中含有 Seata 信息的 HTTP 请求时,可以自动还原 Seata 上下文。
- 支持服务调用者通过 RestTemplate 调用时,自动传递 Seata 上下文。
- 支持服务调用者通过 FeignClient 调用时,自动传递 Seata 上下文。
- 支持 SeataClient 和 Hystrix 同时使用的场景。
- 支持 SeataClient 和 Sentinel 同时使用的场景。
================================================
FILE: spring-cloud-alibaba-examples/seata-example/readme.md
================================================
# Seata Example
## Project description
This project demonstrates how to use Seata Starter to complete the distributed transaction access of Spring Cloud Alibaba application.
[Seata](https://github.com/seata/seata) It is Alibaba's open source distributed transaction middleware, which solves the distributed transaction problems faced by micro-service scenarios in an efficient and zero-intrusion way.
## Preparations
Before you run this sample, you need to complete the following steps:
### 1. Configure the database
> Seata **Notice** actually supports disparate databases for different applications, but Mysql was chosen here for a simple demonstration of how Seata can be used in a Spring Cloud application.
Modify the following configuration in the files under the `application.yml` resources directory in the three applications `account-server`, `order-service`, `storage-service` to the database configuration in the local environment.
```
base:
config:
mdb:
hostname: your mysql server ip address
dbname: your database name for test
port: your mysql server listening port
username: your mysql server username
password: your mysql server password
```
#### Create the undo _ log table
Seata AT mode requires the undo_log table.
```sql
-- Note that 0.3.0+ adds unique index ux_undo_log here
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;
```
#### Import the database tables required by the seata-server db schema
Initializing [global_table、branch_table、lock_table、distributed_lock](https://github.com/seata/seata/blob/2.1.0/script/server/db/mysql.sql) in the database
```sql
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid_and_branch_id` (`xid` , `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
primary key (`lock_key`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
```
#### Create the database tables required by the business in the application sample
```sql
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
### 2. Configure Nacos
> Spring Cloud Alibaba is adapted with Nacos 3.1.0. In this example, Nacos 3.1.0 is used as the configuration center component of Seata.
Create Nacos configuration for Seata: data-id: `seata.properties`, Group: `SEATA_GROUP` (default grouping for seata 2.1.0), import
Add the following configuration items required in the application example to the `seata.properties` configuration file: [事务群组配置](https://seata.io/zh-cn/docs/user/configurations.html)
```properties
service.vgroupMapping.default_tx_group=default # Used to specify the mapping relationship between global transaction groups and local transaction groups.
service.vgroupMapping.order-service-tx-group=default
service.vgroupMapping.account-service-tx-group=default
service.vgroupMapping.business-service-tx-group=default
service.vgroupMapping.storage-service-tx-group=default
```
### 3. Start Seata-server
> Seata 1.5.1 supports console local access. Console address: http://127.0.0.1:7091, you can view the information about the transaction being executed and the global lock information through the built-in console of Seata. When the transaction is finished, the relevant information will be deleted.
#### 1. Download
Click Download [Seata 2.5.0](https://github.com/apache/incubator-seata/releases/tag/v2.5.0) Version. \# The GitHub link is for the source code package, which requires Maven to compile and build the source code and generate the Seata server JAR file.
Or click Download [Apache-seata-2.5.0-incubating-bin.tar.gz](https://seata.apache.org/zh-cn/download/seata-server) . \# Binary package, convenient for debugging with seata-server
#### 2. Configure Seata-server
Modify `seata-server\conf\application.yml` the following configuration items in the configuration file:
- Comment `group: SEATA_GROUP`
- Add Nacos username and password
```yml
seata:
# nacos configuration
config:
type: nacos
nacos:
server-addr: # Nacos service addr
# group: SEATA_GROUP
# namespace: public # Nacos Namespace
username: nacos
password: nacos
data-id: seata.properties # Configuration file name in Nacos
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
registry:
# support: nacos 、 eureka 、 redis 、 zk 、 consul 、 etcd3 、 sofa 、 seata
type: nacos # Using Nacos as a registry center
nacos:
application: seata-server
# group: SEATA_GROUP
# namespace: public # Nacos namespace (make sure to set it to the actual value)
cluster: default
server-addr: # Nacos registry center address
username: nacos
password: nacos
```
- Add store and server settings (example - not required)
```yml
store:
# Support: file, db, redis, raft
mode: db # Using database models
session:
mode: file
lock:
mode: file
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true # MySQL database connection
user: root # MySQL username
password: rootpass # MySQL password
min-conn: 10
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
vgroup-table: vgroup_table
query-limit: 1000
max-wait: 5000
server:
service-port: 8091 # Configure service port
max-commit-retry-timeout: -1
max-rollback-retry-timeout: -1
rollback-failed-unlock-enable: false
enable-check-auth: true
enable-parallel-request-handle: true
enable-parallel-handle-branch: false
retry-dead-threshold: 70000
xaer-nota-retry-timeout: 60000
enableParallelRequestHandle: true
applicationDataLimitCheck: true
applicationDataLimit: 64000
recovery:
committing-retry-period: 1000
async-committing-retry-period: 1000
rollbacking-retry-period: 1000
end-status-retry-period: 1000
timeout-retry-period: 1000
undo:
log-save-days: 7
log-delete-period: 86400000
session:
branch-async-queue-size: 5000 # Asynchronous branch queue size
enable-branch-async-remove: false # Enable branch asynchronous removal
ratelimit:
enable: false
bucketTokenNumPerSecond: 999999
bucketTokenMaxNum: 999999
bucketTokenInitialNum: 999999
metrics:
enabled: false
registry-type: compact
exporter-list: prometheus
exporter-prometheus-port: 9898
transport:
rpc-tc-request-timeout: 15000
enable-tc-server-batch-send-response: false
min-http-pool-size: 10
max-http-pool-size: 100
max-http-task-queue-size: 1000
http-pool-keep-alive-time: 500
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
boss-thread-size: 1
```
> **Notice**
> Nacos 3.1.0 enables authentication. Configuration `username` and `password` properties are required, otherwise login fails. For more Nacos 3.1.0 related configurations, refer to `nacos-example`.
> **The Nacos service registration group when seata-server is started must be consistent with the group in the sample application, otherwise an error that seata-server cannot be found will occur!**
> For more information about the configuration of Seata-server with Nacos as the configuration center, please refer to https://seata.io/zh-cn/docs/ops/deploy-by-docker-compose/#nacos-db.
### 3. Start Seata-server
Windows:
```cmd
./seata-server.bat
```
Linux/Mac
```shell
sh seata-server.sh
```
For more configuration startup parameters, please refer to https://seata.io/zh-cn/docs/user/quickstart/#%E6%AD%A5%E9%AA%A4-4-%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1.
**Notice** If you change the endpoint and the registry uses the default file type, remember that in the `file.conf` file in each sample project, Modify the value of grouplist (when the registry. Type or config. Type in the registry. Conf is file, the file name in the internal file node will be read. If the type is not file, the data will be directly read from the registration configuration center of the corresponding metadata of the configuration type. It is recommended to use nacos as the configuration registration center.
## Run the sample
Start the sample by running `account-server` the Main functions of the, `order-service`, `storage-service`, and `business-service` applications separately.
After starting the sample, access the following URL through the GET method of HTTP to verify `business-service` the scenarios of calling other services through RestTemplate and FeignClient in respectively.
```shell
http://127.0.0.1:18081/seata/feign
http://127.0.0.1:18081/seata/rest
```
When a service interface is invoked, two types of returns are possible
1. SUCCESS: calling interface service succeeded;
2. 500 exception, business-service mock exception.
## How do I verify that a distributed transaction is successful?
### Xid information passed successfully
In `account-server` the Controllers of, `order-service`, and `storage-service` services, the first logic to be executed is to output the Xid information in the RootContext. If the correct Xid information is output, that is, it changes every time. And that Xid of all the services in the same invocation are the same. Then it indicates that the passing and restoring of Seata's Xid is normal.
```bash
# View service operation logs separately (example)
Account Service ... xid: 192.168.44.1:8091:4540309594179612673
Order Service Begin ... xid: 192.168.44.1:8091:4540309594179612673
Storage Service Begin ... xid: 192.168.44.1:8091:4540309594179612673
...
Begin new global transaction [192.168.44.1:8091:4540309594179612673]
```
### Whether the data in the database is consistent
In this example, we simulate a scenario in which a user purchases goods. The Storage Service is responsible for deducting the inventory quantity, the Order Service is responsible for saving the order, and the Account service is responsible for deducting the balance of the user's account.
To demonstrate the sample, we use Random. NextBoolean () to randomly throw exceptions in Order Service and AccountService, simulating a scenario where exceptions randomly occur during service invocation.
If a distributed transaction is in effect, then the following equation should hold
- User's original amount (1000) = user's existing amount + unit price of goods (2) *Number of orders* quantity of goods per order (2)
- Initial quantity of goods (100) = Quantity on hand of goods + Order quantity * Quantity of goods per order (2)
```sql
# Verification example
SELECT * FROM account_tbl;
SELECT * FROM storage_tbl;
SELECT * FROM order_tbl;
```
Note: Since Random.nextBoolean() is used to randomly throw exceptions to simulate transaction exceptions, it is also necessary to verify whether distributed transactions can be rolled back correctly:
If exceptions are thrown in OrderService and AccountService, StorageService should roll back the inventory deduction, and the account balance should also be restored to its initial state.
View the distributed transaction logs: Check the undo_log table and global_table table to ensure that relevant records are deleted or restored during transaction rollback.
## Support points for Spring Cloud
- Service providers that provide services through Spring MVC can automatically restore the Seata context when they receive an HTTP request with Seata information in the header.
- Support the automatic passing of the Seata context when the service caller invokes through the RestTemplate.
- Support the automatic passing of the Seata context when the service caller calls through FeignClient.
- Scenarios where SeataClient and Hystrix are used together are supported.
- Scenarios where SeataClient and Sentinel are used together are supported.
================================================
FILE: spring-cloud-alibaba-examples/seata-example/storage-service/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../../pom.xml4.0.0storage-serviceSpring Cloud Starter Alibaba Seata Example - Storage Servicejarcom.alibaba.cloudspring-cloud-starter-alibaba-seatacom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jorg.apache.logging.log4jlog4j-coreorg.springframework.bootspring-boot-maven-plugin
================================================
FILE: spring-cloud-alibaba-examples/seata-example/storage-service/src/main/java/com/alibaba/cloud/examples/StorageApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author xiaojing
*/
@SpringBootApplication
public class StorageApplication {
public static void main(String[] args) {
SpringApplication.run(StorageApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/storage-service/src/main/java/com/alibaba/cloud/examples/config/DatabaseConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.config;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author xiaojing
*/
@Configuration
public class DatabaseConfiguration {
// druid don't support GraalVM now because of there is CGlib proxy
/*@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSource storageDataSource() {
return new DruidDataSource();
}*/
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("delete from storage_tbl where commodity_code = 'C00321'");
jdbcTemplate.update(
"insert into storage_tbl(commodity_code, count) values ('C00321', 100)");
return jdbcTemplate;
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/storage-service/src/main/java/com/alibaba/cloud/examples/controller/StorageController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.controller;
import org.apache.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xiaojing
*/
@RestController
public class StorageController {
private static final Logger LOGGER = LoggerFactory.getLogger(StorageController.class);
private static final String SUCCESS = "SUCCESS";
private static final String FAIL = "FAIL";
private final JdbcTemplate jdbcTemplate;
public StorageController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@GetMapping(value = "/storage/{commodityCode}/{count}", produces = "application/json")
public String echo(@PathVariable String commodityCode, @PathVariable int count) {
LOGGER.info("Storage Service Begin ... xid: " + RootContext.getXID());
int result = jdbcTemplate.update(
"update storage_tbl set count = count - ? where commodity_code = ?",
new Object[] { count, commodityCode });
LOGGER.info("Storage Service End ... ");
if (result == 1) {
return SUCCESS;
}
return FAIL;
}
}
================================================
FILE: spring-cloud-alibaba-examples/seata-example/storage-service/src/main/resources/application.yml
================================================
base:
config:
mdb:
hostname: 127.0.0.1 #your mysql server ip address
dbname: seata #your database name for test
port: 3306 #your mysql server listening port
username: 'root' #your mysql server username
password: 'root' #your mysql server password
server:
port: 18082
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
application:
name: storage-service
main:
allow-bean-definition-overriding: true
datasource:
name: storageDataSource
# druid don't support GraalVM now because of there is CGlib proxy
# type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${base.config.mdb.hostname}:${base.config.mdb.port}/${base.config.mdb.dbname}?useSSL=false&serverTimezone=UTC
username: ${base.config.mdb.username}
password: ${base.config.mdb.password}
# druid:
# max-active: 20
# min-idle: 2
# initial-size: 2
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-tx-group
config:
type: nacos
nacos:
serverAddr: 127.0.0.1:8848
dataId: "seata.properties"
group: SEATA_GROUP
username: 'nacos'
password: 'nacos'
registry:
type: nacos
nacos:
cluster: default
group: SEATA_GROUP
application: seata-server
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/README-zh.md
================================================
# Spring Cloud Alibaba Sentinel Example
## 项目说明
本 Example 项目演示如何使用 `spring-cloud-starter-alibaba-sentinel` 完成 Spring Cloud 应用中的流量治理功能。
[Sentinel](https://github.com/alibaba/Sentinel) 是阿里巴巴开源的分布式系统的流量防卫组件,Sentinel 以流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。
## Sentinel Example
在本 Example 项目中,主要演示 Sentinel 断路器,整合 Spring Cloud Gateway 和 OpenFeign、RestTemplate 以及 Webclient 的使用。
### 下载并启动 Sentinel Console
1. 首先需要获取 Sentinel 控制台,Sentinel Console 支持直接下载和源码构建两种方式
1. 直接下载:[下载 Sentinel 控制台](https://github.com/alibaba/Sentinel/releases)
2. 源码构建:进入 Sentinel [Github 项目页面](https://github.com/alibaba/Sentinel),将代码 clone 到本地自行编译打包,[参考此文档](https://github.com/alibaba/Sentinel/blob/1.8/sentinel-dashboard/README.md)。
2. 启动控制台,执行 Java 命令 `java -jar sentinel-dashboard.jar` 完成 Sentinel 控制台的启动。
控制台默认的监听端口为 `8080`。Sentinel 控制台使用 Spring Boot 编程模型开发,如果需要指定其他端口,请使用 Spring Boot 容器配置的标准方式,详情请参考 [Spring Boot 文档](https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-customizing-embedded-containers)。
### Sentinel Core Example
在此 Example 模块中,主要演示如何使用 Sentinel 的基本功能完成 Spring Cloud 应用的流量管控。 在启动 Example 进行演示之前,先了解一下如何在 Spring Cloud 应用中接入 Sentinel 组件。
#### 项目编写
> **注意:本文档只是为了便于理解接入方式。本示例代码中已经完成接入工作,您无需再进行修改。**
1. 首先,修改 `pom.xml` 文件,引入 Sentinel starter。
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-sentinel
```
2. 接入限流埋点
- HTTP 埋点
`spring-cloud-starter-alibaba-sentinel` 默认为所有的 HTTP 服务提供了限流埋点,如果只想对 HTTP 服务进行限流,那么只需要引入依赖,无需修改代码。
- 自定义埋点
如果需要对某个特定的方法进行限流或降级,可以通过 `@SentinelResource` 注解来完成限流的埋点,示例代码如下:
```java
@SentinelResource("resource")
public String hello() {
return "Hello";
}
```
当然也可以通过原始的 `SphU.entry(xxx)` 方法进行埋点,可以参见 [Sentinel 文档](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%B5%84%E6%BA%90)。
3. 配置限流规则
Sentinel 提供了两种配置限流规则的方式:代码配置 和 控制台配置。本示例使用的方式为通过代码配置。
1. 通过代码来实现限流规则的配置。一个简单的限流规则配置示例代码如下,更多限流规则配置详情请参考 [Sentinel 文档](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%A7%84%E5%88%99)。
```java
List rules = new ArrayList();
FlowRule rule = new FlowRule();
rule.setResource(str);
// set limit qps to 10
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
```
2. 通过控制台进行限流规则配置请参考文章后面的图文说明。
#### 应用启动
1. 增加配置,在应用的 `/src/main/resources/application.yml` 中添加基本配置信息
```yaml
server:
port: 18083
spring:
application:
name: sentinel-core-example
cloud:
sentinel:
transport:
dashboard: localhost:8080
```
2. 启动应用,支持 IDE 直接启动和编译打包后启动。
1. IDE直接启动:找到主类 `SentinelCoreApplication`,执行 main 方法启动应用。
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-core-example.jar` 启动应用。
#### 调用服务验证
使用 curl 命令分别调用两个 URL,可以看到访问成功。
```shell
$ curl http://localhost:18083/test
Blocked by Sentinel (flow limiting)
$ curl http://localhost:18083/hello
Hello
```
#### 配置限流规则并验证
1. 访问 http://localhost:8080 页面,进行登陆,默认用户名和密码均为:`sentinel`。
可以在左侧看到 `sentinel-core-example` 应用已经注册到了控制台,单击 **流控规则** ,可以看到目前的流控规则为空。
> **注意:如果您在控制台没有找到应用,请调用一下进行了 Sentinel 埋点的 URL 或方法,因为 Sentinel 使用了 lazy load 策略。详细的排查过程请参见 [Sentinel FAQ](https://github.com/alibaba/Sentinel/wiki/FAQ)。**
2. 配置 URL 限流规则:点击新增流控规则,资源名填写需要限流的 URL 相对路径,单机阈值选择需要限流的阈值,点击新增进行确认。(为了便于演示效果,这里将值设置成了 1)。
3. 配置自定义限流规则:点击新增流控规则,资源名填写 `@SentinelResource` 注解 `value` 字段的值,单机阈值选择需要限流的阈值,点击新增进行确认。(为了便于演示效果,这里将值设置成了 1)。
4. 访问 URL,当 QPS 超过 1 时,可以看到限流效果如下。

#### 自定义限流处理逻辑
* 默认限流异常处理
URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。 如果需要自定义处理逻辑,实现的方式如下:
```java
public class CustomUrlBlockHandler implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
// todo add your logic
}
}
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
```
* 使用 `@SentinelResource` 注解下的限流异常处理
如果需要自定义处理逻辑,填写 `@SentinelResource` 注解的 `blockHandler` 属性(针对所有类型的 `BlockException`,需自行判断)或 `fallback` 属性(针对熔断降级异常),注意**对应方法的签名和位置有限制**,详情见 [Sentinel 注解支持文档](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81#sentinelresource-%E6%B3%A8%E8%A7%A3)。示例实现如下:
```java
public class TestService {
// blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制.
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
public void test() {
System.out.println("Test");
}
// blockHandler 是位于当前类下的 exceptionHandler 方法,需符合对应的类型限制.
@SentinelResource(value = "hello", blockHandler = "exceptionHandler")
public String hello(long s) {
return String.format("Hello at %d", s);
}
public String exceptionHandler(long s, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
}
public final class ExceptionUtil {
public static void handleException(BlockException ex) {
System.out.println("Oops: " + ex.getClass().getCanonicalName());
}
}
```
一个简单的 `@SentinelResource` 示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/2021.x/sentinel-demo/sentinel-demo-annotation-spring-aop)。
### Sentinel Circuitbreaker Example
本 Example 主要演示 OpenFeign 整合 Sentinel 断路器的使用。
#### 准备配置文件
1. 添加配置到配置中心。dataId 为 `sentinel-circuitbreaker-rules.yml`
```yml
feign:
circuitbreaker:
enabled: true # 开启 feign 断路器支持
sentinel:
default-rule: default # 默认规则名称
rules:
# 默认规则, 对所有 feign client 生效
default:
- grade: 2 # 根据异常数目降级
count: 1
timeWindow: 15 # 降级后到半开状态的时间
statIntervalMs: 1000
minRequestAmount: 1
# 只对 feign client user 生效
user:
- grade: 2
count: 1
timeWindow: 15
statIntervalMs: 1000
minRequestAmount: 1
# 只对 feign client user 的方法 feignMethod 生效
# 括号里是参数类型, 多个逗号分割, 比如 user#method(boolean,String,Map)
"[user#feignMethod(boolean)]":
- grade: 2
count: 1
timeWindow: 10
statIntervalMs: 1000
minRequestAmount: 1
```
#### 验证配置生效
启动项目主类 `FeignCircuitBreakerApplication`
##### 验证默认 Feign client 生效
先访问 http://localhost/test/default/false 2 次 (1秒内)
再访问 http://localhost/test/default/true 断路器处于打开状态
##### 验证指定 Feign client 生效
先访问 http://localhost/test/feign/false 2 次 (1秒内)
再访问 http://localhost/test/feign/true 断路器处于打开状态
##### 验证 Feign client 指定方法生效
先访问 http://localhost/test/feignMethod/false 2次 (1秒内)
再访问 http://localhost/test/feignMethod/true 断路器处于打开状态
#### 规则动态刷新
修改配置中心的规则, 再访问上述接口。
### Sentinel OpenFeign Example
本 Example 演示 OpenFeing 与 Sentinel 的整合。Example 中使用 httpbin 充当后台 API 接口服务。
#### 项目编写
> **注意:本项目中代码已经完成相对应的功能,不需要再进行任何修改。**
项目支持两种启动方式:通过主类 `OpenFeignApplication` 启动和 Jar 包启动两种方式。
#### 调用测试
项目启动完成之后,可以通过访问对应的 URL 访问,查看对应的 Sentinel 流控效果。
> **注意:项目中提供的 RestTemplate 和 Webclient Example 同理。**
## Endpoint 信息查看
Spring Boot 应用支持通过 Endpoint 来暴露相关信息,`spring-cloud-starter-alibaba-sentinel` 也支持这一点。
在使用之前需要在 Maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`
Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/actuator/sentinel 来访问。
## ReadableDataSource 支持
Sentinel 内部提供了[动态规则的扩展实现 ReadableDataSource](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95)。
Sentinel starter 整合了目前存在的几类 ReadableDataSource。只需要在配置文件中进行相关配置,即可在 Spring 容器中自动注册 DataSource。
比如要定义两个ReadableDataSource,分别是 `FileRefreshableDataSource` 和 `NacosDataSource`,配置如下:
```properties
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
```
`ds1` 和 `ds2` 表示ReadableDataSource的名称,可随意编写。`ds1` 和 `ds2` 后面的 `file` 和 `nacos` 表示ReadableDataSource的类型。
目前支持`file`, `nacos`, `zk`, `apollo`,`redis` 这5种类型。
其中`nacos`,`zk`,`apollo`,`redis` 这4种类型的使用需要加上对应的依赖`sentinel-datasource-nacos`, `sentinel-datasource-zookeeper`, `sentinel-datasource-apollo`, `sentinel-datasource-redis`。
当 `ReadableDataSource` 加载规则数据成功的时候,控制台会打印出相应的日志信息:
```
[Sentinel Starter] DataSource ds1-sentinel-file-datasource load 3 DegradeRule
[Sentinel Starter] DataSource ds2-sentinel-nacos-datasource load 2 FlowRule
```
## More
Sentinel 是一款功能强大的中间件,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。此 Demo 仅演示了 使用 Sentinel 作为限流工具的使用,更多 Sentinel 相关的信息,请参考 [Sentinel 项目](https://github.com/alibaba/Sentinel)。
如果您对 `spring-cloud-starter-alibaba-sentinel` 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/README.md
================================================
# Spring Cloud Alibaba Sentinel Example
## Project description
This Example project demonstrates how to use `spring-cloud-starter-alibaba-sentinel` to complete the traffic management function in Spring Cloud applications.
[Sentinel](https://github.com/alibaba/Sentinel) It is the traffic defense component of Alibaba's open source distributed system. Sentinel takes traffic as the entry point to protect the stability of services from multiple dimensions such as traffic control, fuse degradation, system load protection, etc.
## Sentinel Example
In this Example project, the Sentinel circuit breaker is mainly demonstrated, and the Spring Cloud Gateway is integrated with the use of OpenFeign, RestTemplate, and Webclient.
### Download and launch Sentinel Console
1. First, you need to obtain the Sentinel Console, which supports direct download and source code construction
1. Direct download: [Download the Sentinel console](https://github.com/alibaba/Sentinel/releases)
2. Source code construction: Enter Sentinel [Github project page](https://github.com/alibaba/Sentinel), clone the code to the local compilation and packaging [参考此文档](https://github.com/alibaba/Sentinel/blob/1.8/sentinel-dashboard/README.md).
2. Start the console and execute the Java command `java -jar sentinel-dashboard.jar` to finish starting the Sentinel console.
The default console listening port is `8080`. The Sentinel console is developed using the Spring Boot programming model. If you need to specify other ports, please use the standard method of Spring Boot container configuration. For details, please refer to [Spring Boot documentation](https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-customizing-embedded-containers).
### Sentinel Core Example
This Example module mainly demonstrates how to use the basic functions of Sentinel to complete the traffic control of Spring Cloud applications. Before launching Example for a demonstration, let's look at how to access the Sentinel component in a Spring Cloud application.
#### Project preparation
> **Note: This document is only for the purpose of understanding the access method. The access work is done in this sample code, and you do not need to modify it.**
1. First, modify `pom.xml` the file to introduce Sentinel starter.
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-sentinel
```
2. Access current-limiting buried point
- `spring-cloud-starter-alibaba-sentinel` By default, all HTTP services provide the current limiting embedded point. If you only want to limit the current of the HTTP service, you only need to introduce the dependency and do not need to modify the code.
- Custom Buried Point If you need to limit or degrade a specific method, you can use `@SentinelResource` annotations to complete the current limiting buried point. The example code is as follows:
```java
@SentinelResource("resource")
public String hello() {
return "Hello";
}
```
Of course, it can also be buried by the original `SphU.entry(xxx)` method, which can be seen [Sentinel documentation](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%B5%84%E6%BA%90).
3. Configure the current limit rule
Sentinel provides two ways to configure throttling rules: code configuration and console configuration. The method used in this example is configuration through code.
1. Configure rate limits by code. Here is a simple code example of rate limit configuration. For more configuration details, see [Sentinel documentation](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%A7%84%E5%88%99).
```java
List rules = new ArrayList();
FlowRule rule = new FlowRule();
rule.setResource(str);
// set limit qps to 10
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
```
2. Please refer to the graphic description at the end of the article for current limiting rule configuration through the console.
#### The application starts
1. Add configuration, and add basic configuration information in the application `/src/main/resources/application.yml`
```yaml
server:
port: 18083
spring:
application:
name: sentinel-core-example
cloud:
sentinel:
transport:
dashboard: localhost:8080
```
2. Start the application, support IDE direct start and start after compilation and packaging.
1. IDE direct startup: find the main class `SentinelCoreApplication` and execute the main method to start the application.
2. Start after packaging and compiling: First execute `mvn clean package` to package the project compilation, and then execute `java -jar sentinel-core-example.jar` to start the application.
#### Invoke service validation
Use the curl command to call the two URLs separately, and you can see that the access is successful.
```shell
$ curl http://localhost:18083/test
Blocked by Sentinel (flow limiting)
$ curl http://localhost:18083/hello
Hello
```
#### Configure and verify the current limit rule
1. Visit the http://localhost:8080 page and log in. The default user name and password are: `sentinel`.
On the left, you can see that the Sentinel-Example application has been registered to the console. Click **Flow control rules** it, and you can see that the current flow control rule is empty.
> ** Note: If you do not find the application in the console, please call the URL or method with Sentinel buried points, because Sentinel uses lazy load policy. For detailed troubleshooting procedures, see [Sentinel FAQ](https://github.com/alibaba/Sentinel/wiki/FAQ). **
2. Configure URL flow limit rule: click Add Flow Control Rule, fill in the URL relative path to be restricted for the resource name, select the threshold to be restricted for the single machine threshold, and click Add to confirm. (The value is set to 1 for demonstration purposes.).
3. Configure custom current limiting rules: click Add a flow control rule, fill in `@SentinelResource` the value of the comment `value` field for the resource name, select the threshold for current limiting for the single machine threshold, and click Add to confirm. (The value is set to 1 for demonstration purposes.).
4. Visit the URL. When the QPS exceeds 1, you can see the effect of limiting the current as follows.
#### Custom current limit processing logic
* Default Current Limit Exception Handling
After the URL current limiting is triggered, the default processing logic is to directly return to "Blocked by Sentinel". If you need to customize the processing logic, the implementation method is as follows:
```java
public class CustomUrlBlockHandler implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
// todo add your logic
}
}
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
```
* Current limit exception handling using `@SentinelResource` annotations
If you need to customize the processing logic, fill in `@SentinelResource` the attribute of the note `blockHandler` (for all types `BlockException`, you need to make your own judgment) or `fallback` the attribute (for the fuse degradation exception). **There are restrictions on the signature and location of the corresponding method** See for [Sentinel Annotation Support Document](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81#sentinelresource-%E6%B3%A8%E8%A7%A3) details. An example implementation is as follows:
```java
public class TestService {
// blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制.
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
public void test() {
System.out.println("Test");
}
// blockHandler 是位于当前类下的 exceptionHandler 方法,需符合对应的类型限制.
@SentinelResource(value = "hello", blockHandler = "exceptionHandler")
public String hello(long s) {
return String.format("Hello at %d", s);
}
public String exceptionHandler(long s, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
}
public final class ExceptionUtil {
public static void handleException(BlockException ex) {
System.out.println("Oops: " + ex.getClass().getCanonicalName());
}
}
```
A simple `@SentinelResource` example can be found in [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/2021.x/sentinel-demo/sentinel-demo-annotation-spring-aop).
### Sentinel Circuitbreaker Example
This Example mainly demonstrates the use of OpenFeign integrated Sentinel circuit breaker.
#### Prepare the configuration file
1. Add a configuration to the Configuration Center. DataId is `sentinel-circuitbreaker-rules.yml`
```yml
feign:
circuitbreaker:
enabled: true # 开启 feign 断路器支持
sentinel:
default-rule: default # 默认规则名称
rules:
# 默认规则, 对所有 feign client 生效
default:
- grade: 2 # 根据异常数目降级
count: 1
timeWindow: 15 # 降级后到半开状态的时间
statIntervalMs: 1000
minRequestAmount: 1
# 只对 feign client user 生效
user:
- grade: 2
count: 1
timeWindow: 15
statIntervalMs: 1000
minRequestAmount: 1
# 只对 feign client user 的方法 feignMethod 生效
# 括号里是参数类型, 多个逗号分割, 比如 user#method(boolean,String,Map)
"[user#feignMethod(boolean)]":
- grade: 2
count: 1
timeWindow: 10
statIntervalMs: 1000
minRequestAmount: 1
```
#### Verify that the configuration is in effect
Start the project main class `FeignCircuitBreakerApplication`
##### Verify that the default Feign client takes effect
Access http://localhost/test/default/false 2 times (within 1 second) and then access http://localhost/test/default/true the circuit breaker in the open state
##### Verify that the specified Feign client is in effect
Access http://localhost/test/feign/false 2 times (within 1 second) and then access http://localhost/test/feign/true the circuit breaker in the open state
##### Verify that the Feign client specified method takes effect
Access http://localhost/test/feignMethod/false 2 times (within 1 second) and then access http://localhost/test/feignMethod/true the circuit breaker in the open state
#### Rule dynamic refresh
Modify the rules of the configuration center, and then access the above interface.
### Sentinel OpenFeign Example
This Example demonstrates the integration of OpenFeing and Sentinel. In Example, httpbin is used as a background API interface service.
#### Project preparation
> **Note: The code in this project has completed the corresponding function and does not need to be modified.**
The project supports two startup modes: startup through the main class `OpenFeignApplication` and startup through the Jar package.
#### Call the test
After the project is started, you can access the corresponding URL to view the corresponding Sentinel flow control effect.
> **Note: The RestTemplate provided in the project is the same as the Webclient Example.**
## Endpoint information viewing
Spring Boot applications support the exposure of relevant information through Endpoints, `spring-cloud-starter-alibaba-sentinel` as well.
Before using it, you need to add `spring-boot-starter-actuator` dependencies in Maven and allow Endpoints access in the configuration.
* Add configuration in Spring Boot 1.x
* Adding Configuration in Spring Boot 2.x
Spring Boot 1.x can view Sentinel Endpoint information by visiting http://127.0.0.1:18083/sentinel . Spring Boot 2.x can be accessed by visiting http://127.0.0.1:18083/actuator/sentinel .
## View real-time monitoring
The Sentinel console supports real-time monitoring and viewing. You can view information such as the number of requests passed and the number of throttled flows for each link through the Sentinel console. Where `p_qps` is a pass flow controlled QPS and `b_qps` is a blocked QPS.
## ReadableData Source support
The Sentinel provides [Implementation of ReadableDataSource by Extending Dynamic Rule](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95) internally.
Sentinel starter incorporates several classes of ReadableDataSources that exist today. The DataSource is automatically registered in the Spring container by simply making the relevant configuration in the configuration file.
`FileRefreshableDataSource` and `NacosDataSource`, configured as follows:
```properties
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
```
`ds1` And `ds2` the name that represents the ReadableDataSource. Feel free to write. The sum `nacos` following `file` the `ds1` and `ds2` represents the type of the ReadableDataSource.
Currently supports `file`, `nacos`, `zk` `apollo`, `redis` these 5 types.
Among them `nacos` `zk` `apollo`, the use of `redis` these four types requires the addition of corresponding dependencies `sentinel-datasource-nacos` `sentinel-datasource-zookeeper` `sentinel-datasource-apollo` `sentinel-datasource-redis`.
When `ReadableDataSource` the rule data is loaded successfully, the console will print out the corresponding log information:
```
[Sentinel Starter] DataSource ds1-sentinel-file-datasource load 3 DegradeRule
[Sentinel Starter] DataSource ds2-sentinel-nacos-datasource load 2 FlowRule
```
## More
Sentinel is a powerful middleware that protects the stability of services from multiple dimensions such as flow control, fuse degradation, and system load protection. This Demo only demonstrates the use of Sentinel as a current limiting tool. For more information about Sentinel, please refer to [Project Sentinel](https://github.com/alibaba/Sentinel).
If you `spring-cloud-starter-alibaba-sentinel` have any suggestions or ideas, please feel free to send them to us in the issue or through other community channels.
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0sentinel-circuitbreaker-exampleSpring Cloud Starter Alibaba Sentinel - Feign With Sentinel CircuitBreaker ExampleExample demonstrating how to use sentinel circuit breaker with feignjarorg.springframework.bootspring-boot-starter-weborg.springframework.cloudspring-cloud-starter-openfeigncom.alibaba.cloudspring-cloud-circuitbreaker-sentinelcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/java/com/alibaba/cloud/examples/FeignCircuitBreakerApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author freeman
*/
@SpringBootApplication
@EnableFeignClients
public class FeignCircuitBreakerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignCircuitBreakerApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/java/com/alibaba/cloud/examples/controller/ApiController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
*
*
* @author freeman
*/
@RestController
public class ApiController {
@GetMapping("/default/{ok}")
public String defaultConfig(@PathVariable boolean ok) {
if (ok) {
return "ok";
}
throw new RuntimeException("fail");
}
@GetMapping("/feign/{ok}")
public String feignConfig(@PathVariable boolean ok) {
if (ok) {
return "ok";
}
throw new RuntimeException("fail");
}
@GetMapping("/feignMethod/{ok}")
public String feignMethodConfig(@PathVariable boolean ok) {
if (ok) {
return "ok";
}
throw new RuntimeException("fail");
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/java/com/alibaba/cloud/examples/controller/TestController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.controller;
import com.alibaba.cloud.examples.feign.OrderClient;
import com.alibaba.cloud.examples.feign.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
*
*
* @author freeman
*/
@RestController
public class TestController {
@Autowired
private UserClient userClient;
@Autowired
private OrderClient orderClient;
@GetMapping("/test/default/{ok}")
public String testDefault(@PathVariable boolean ok) {
return orderClient.defaultConfig(ok);
}
@GetMapping("/test/feign/{ok}")
public String testFeign(@PathVariable boolean ok) {
return userClient.feign(ok);
}
@GetMapping("/test/feignMethod/{ok}")
public String testFeignMethod(@PathVariable boolean ok) {
return userClient.feignMethod(ok);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/java/com/alibaba/cloud/examples/feign/OrderClient.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
*
*
* @author freeman
*/
@FeignClient(value = "order", url = "http://localhost:${server.port}", fallback = OrderClientFallBack.class)
public interface OrderClient {
@GetMapping("/default/{ok}")
String defaultConfig(@PathVariable boolean ok);
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/java/com/alibaba/cloud/examples/feign/OrderClientFallBack.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import org.springframework.stereotype.Component;
/**
*
*
* @author freeman
*/
@Component
public class OrderClientFallBack implements OrderClient {
@Override
public String defaultConfig(boolean ok) {
return "order fallback";
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/java/com/alibaba/cloud/examples/feign/UserClient.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
*
*
* @author freeman
*/
@FeignClient(value = "user", url = "http://localhost:${server.port}", fallback = UserClientFallBack.class)
public interface UserClient {
@GetMapping("/feignMethod/{ok}")
String feignMethod(@PathVariable boolean ok);
@GetMapping("/feign/{ok}")
String feign(@PathVariable boolean ok);
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/java/com/alibaba/cloud/examples/feign/UserClientFallBack.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.feign;
import org.springframework.stereotype.Component;
/**
*
*
* @author freeman
*/
@Component
public class UserClientFallBack implements UserClient {
@Override
public String feignMethod(boolean ok) {
return "user fallback";
}
@Override
public String feign(boolean ok) {
return "user fallback";
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/resources/application.yml
================================================
#
# Copyright 2023-2024 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
server:
port: 80
spring:
application:
name: sentinel-circuit-breaker-example
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
username: 'nacos'
password: 'nacos'
config:
import: optional:nacos:sentinel-circuitbreaker-rules.yml
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example/src/main/resources/sentinel-circuitbreaker-rules.yml
================================================
#
# Copyright 2023-2024 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
spring:
cloud:
openfeign:
circuitbreaker:
enabled: true
feign:
sentinel:
default-rule: default
rules:
# global feign client
default:
- grade: 2
count: 1
timeWindow: 15
statIntervalMs: 1000
minRequestAmount: 1
# specific feign client
user:
- grade: 2
count: 1
timeWindow: 15
statIntervalMs: 1000
minRequestAmount: 1
# specific feign client single method
"[user#feignMethod(boolean)]":
- grade: 2
count: 1
timeWindow: 10
statIntervalMs: 1000
minRequestAmount: 1
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0sentinel-core-exampleSpring Cloud Starter Alibaba Sentinel Core ExampleExample demonstrating how to use sentineljarcom.alibaba.cloudspring-cloud-starter-alibaba-sentinelcom.alibaba.cloudspring-cloud-alibaba-sentinel-datasourceorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-thymeleafcom.alibaba.cspsentinel-datasource-nacosorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/com/alibaba/cloud/examples/ExceptionUtil.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
/**
* @author fangjian
*/
public final class ExceptionUtil {
private ExceptionUtil() {
}
public static SentinelClientHttpResponse handleException(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
System.out.println("Oops: " + ex.getClass().getCanonicalName());
return new SentinelClientHttpResponse("custom block info");
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/com/alibaba/cloud/examples/JsonFlowRuleListConverter.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.List;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
/**
* @author fangjian
*/
public class JsonFlowRuleListConverter implements Converter> {
@Override
public List convert(String source) {
return JSON.parseObject(source, new TypeReference>() {
});
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/com/alibaba/cloud/examples/SentinelCoreApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.Collections;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelCircuitBreakerFactory;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelConfigBuilder;
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaojing
*/
@SpringBootApplication
public class SentinelCoreApplication {
@Bean
@SentinelRestTemplate(blockHandler = "handleException",
blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public RestTemplate restTemplate2() {
return new RestTemplate();
}
@Bean
public Converter myConverter() {
return new JsonFlowRuleListConverter();
}
@Bean
public Customizer defaultConfig() {
return factory -> {
factory.configureDefault(
id -> new SentinelConfigBuilder().resourceName(id)
.rules(Collections.singletonList(new DegradeRule(id)
.setGrade(RuleConstant.DEGRADE_GRADE_RT).setCount(100)
.setTimeWindow(10)))
.build());
};
}
public static void main(String[] args) {
SpringApplication.run(SentinelCoreApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/com/alibaba/cloud/examples/TestController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaojing
*/
@RestController
public class TestController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private CircuitBreakerFactory circuitBreakerFactory;
@GetMapping("/hello")
@SentinelResource("resource")
public String hello() {
return "Hello";
}
@GetMapping("/aa")
@SentinelResource("aa")
public String aa(int b, int a) {
return "Hello test";
}
@GetMapping("/test")
public String test1() {
return "Hello test";
}
@GetMapping("/template")
public String client() {
return restTemplate.getForObject("http://www.taobao.com/test", String.class);
}
@GetMapping("/slow")
public String slow() {
return circuitBreakerFactory.create("slow").run(() -> {
try {
Thread.sleep(500L);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return "slow";
}, throwable -> "fallback");
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/com/alibaba/cloud/examples/WebMvcConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author yuhuangbin
*/
@Configuration
@EnableWebMvc
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/errorPage").setViewName("errorPage");
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.yml
================================================
#
# Copyright 2023-2024 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
spring:
application:
name: sentinel-core-example
cloud:
sentinel:
transport:
dashboard: localhost:8080
datasource:
ds1:
file:
file: classpath:flowrule.json
data-type: json
rule-type: flow
ds2:
file:
file: classpath:degraderule.json
data-type: json
rule-type: degrade
ds3:
file:
file: classpath:authority.json
data-type: json
rule-type: authority
ds4:
file:
file: classpath:system.json
data-type: json
rule-type: system
ds5:
file:
file: classpath:param-flow.json
data-type: json
rule-type: param_flow
ds6:
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
data-id: flowrule.json
data-type: json
rule-type: flow
block-page: /errorPage
# filter:
# enabled: false
# http-method-specify: false
eager: true
server:
port: 18083
management:
endpoint:
web:
exposure:
include: "*"
health:
show-details: always
diskSpace:
# we can disable health check, default is enable
enabled: false
# sentinel:
# enabled: false
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/authority.json
================================================
[
{
"resource": "good",
"limitApp": "abc",
"strategy": 0
},
{
"resource": "bad",
"limitApp": "bcd",
"strategy": 1
},
{
"resource": "terrible",
"limitApp": "aaa",
"strategy": 1
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/degraderule.json
================================================
[
{
"resource": "aa",
"count": 20.0,
"grade": 0,
"passCount": 0,
"timeWindow": 10
},
{
"resource": "abc1",
"count": 15.0,
"grade": 0,
"passCount": 0,
"timeWindow": 10
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json
================================================
[
{
"resource": "/hello",
"controlBehavior": 0,
"count": 1,
"grade": 1,
"limitApp": "default",
"strategy": 0
},
{
"resource": "/test",
"controlBehavior": 0,
"count": 0,
"grade": 1,
"limitApp": "default",
"strategy": 0
},
{
"resource": "GET:http://www.taobao.com",
"controlBehavior": 0,
"count": 0,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.xml
================================================
resource011default0test011default0
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/param-flow.json
================================================
[
{
"resource": "aa",
"count": 0,
"grade": 1,
"limitApp": "default",
"paramIdx": 0,
"paramFlowItemList": [
{
"object": "2",
"classType": "int",
"count": 1
}
]
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/system.json
================================================
[
{
"highestSystemLoad": -1,
"qps": 100,
"avgRt": -1,
"maxThread": 10
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/templates/errorPage.html
================================================
Title
This is error page.
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0sentinel-openfeign-exampleSpring Cloud Starter Alibaba Sentinel x Feign - ExampleExample demonstrating how to use sentinel with feignjarorg.springframework.bootspring-boot-starter-weborg.springframework.cloudspring-cloud-starter-openfeigncom.alibaba.cloudspring-cloud-starter-alibaba-sentinelorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/java/com/alibaba/cloud/examples/OpenFeignApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author raozihao
* @author Steve
*/
@EnableFeignClients
@SpringBootApplication
public class OpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(OpenFeignApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/java/com/alibaba/cloud/examples/configuration/EchoServiceFallbackFactory.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* @author raozihao
* @author Steve
*/
@Component
public class EchoServiceFallbackFactory implements FallbackFactory {
@Override
public HttpbinClientFallback create(Throwable throwable) {
return new HttpbinClientFallback(throwable);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/java/com/alibaba/cloud/examples/configuration/HttpbinClient.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* Provide the external exposure interface of the service calling client.
*
* @author raozihao
* @author Steve
*/
@FeignClient(name = "openfeign-example", url = "https://httpbin.org", contextId = "openfeign-example", fallbackFactory = EchoServiceFallbackFactory.class)
public interface HttpbinClient {
@GetMapping("/delay/3")
String delay();
@GetMapping("/status/500")
String status500();
@GetMapping("/get")
String get();
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/java/com/alibaba/cloud/examples/configuration/HttpbinClientFallback.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
/**
* When the service is blown, the fallback operation is performed.
*
* @author raozihao
*/
public class HttpbinClientFallback implements HttpbinClient {
@Override
public String delay() {
return "delay degrade by sentinel";
}
@Override
public String status500() {
return "500 degrade by sentinel";
}
@Override
public String get() {
return "get degrade by sentinel";
}
private Throwable throwable;
HttpbinClientFallback(Throwable throwable) {
this.throwable = throwable;
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/java/com/alibaba/cloud/examples/configuration/SentinelRulesConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;
/**
* @author raozihao
* @author Steve
*/
@Component
public class SentinelRulesConfiguration {
/**
* You can configure sentinel rules by referring.
* https://sca.aliyun.com/docs/2023/user-guide/sentinel/advanced-guide/#%E6%9B%B4%E5%A4%9A%E9%85%8D%E7%BD%AE%E9%A1%B9
*/
@PostConstruct
public void init() {
System.out.println("Load Sentinel Rules start!");
List flowRules = new ArrayList();
FlowRule flowRule = new FlowRule();
flowRule.setResource("GET:https://httpbin.org/get");
flowRule.setCount(1);
flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
flowRule.setStrategy(RuleConstant.STRATEGY_DIRECT);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
List degradeRules = new ArrayList();
DegradeRule degradeRule1 = new DegradeRule();
degradeRule1.setResource("GET:https://httpbin.org/status/500");
degradeRule1.setCount(1);
degradeRule1.setMinRequestAmount(1);
degradeRule1.setTimeWindow(30);
degradeRule1.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
degradeRule1.setLimitApp("default");
degradeRules.add(degradeRule1);
DegradeRule degradeRule2 = new DegradeRule();
degradeRule2.setResource("GET:https://httpbin.org/delay/3");
degradeRule2.setCount(1);
degradeRule2.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule2.setSlowRatioThreshold(0.1);
degradeRule2.setMinRequestAmount(1);
degradeRule2.setTimeWindow(30);
degradeRule2.setLimitApp("default");
degradeRules.add(degradeRule2);
DegradeRuleManager.loadRules(degradeRules);
System.out.println("Load Sentinel Rules end!");
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/java/com/alibaba/cloud/examples/controller/TestController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.controller;
import com.alibaba.cloud.examples.configuration.HttpbinClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author raozihao
* @author Steve
*/
@RestController
public class TestController {
@Autowired
private HttpbinClient httpbinClient;
@GetMapping("/rt")
public String delay() {
return httpbinClient.delay();
}
@GetMapping("/exp")
public String exp() {
return httpbinClient.status500();
}
@GetMapping("/get")
public String get() {
return httpbinClient.get();
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/resources/application.yml
================================================
#
# Copyright 2023-2024 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
server:
port: 18087
spring:
application:
name: sentinel-openfeign-example
cloud:
sentinel:
transport:
dashboard: localhost:8080
eager: true
# Don't support run in jar by using configuration file method now, refer to https://github.com/alibaba/spring-cloud-alibaba/issues/3033
# datasource:
# ds1.file:
# file: "classpath: degraderule.json"
# ruleType: "degrade"
# dataType: "json"
# ds2.file:
# file: "classpath: flowrule.json"
# ruleType: "flow"
# dataType: "json"
feign:
sentinel:
enabled: true
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/resources/degraderule.json
================================================
[
{
"resource": "GET:https://httpbin.org/status/500",
"count": 1,
"grade": 2,
"minRequestAmount": 1,
"timeWindow": 30
},
{
"resource": "GET:https://httpbin.org/delay/3",
"count": 1,
"grade": 0,
"slowRatioThreshold": 0.1,
"minRequestAmount": 1,
"timeWindow": 30
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-openfeign-example/src/main/resources/flowrule.json
================================================
[
{
"resource": "GET:https://httpbin.org/get",
"controlBehavior": 0,
"count": 1,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0sentinel-resttemplate-exampleSpring Cloud Starter Alibaba Sentinel x RestTemplate - ExampleExample demonstrating how to use sentinel with RestTemplatejarorg.springframework.bootspring-boot-starter-webcom.alibaba.cloudspring-cloud-starter-alibaba-sentinelorg.springframework.bootspring-boot-starter-testtestorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/main/java/com/alibaba/cloud/examples/RestTemplateApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author raozihao
* @author Steve
*/
@SpringBootApplication
public class RestTemplateApplication {
public static void main(String[] args) {
SpringApplication.run(RestTemplateApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/main/java/com/alibaba/cloud/examples/configuration/RestTemplateConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author raozihao
* @author Steve
*/
@Configuration
public class RestTemplateConfiguration {
@LoadBalanced
@Bean
@SentinelRestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/main/java/com/alibaba/cloud/examples/configuration/SentinelRulesConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.configuration;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;
/**
* @description
* @author ChengPu raozihao
* @date 2023/2/11
*/
@Component
public class SentinelRulesConfiguration {
/**
* You can configure sentinel rules by referring.
* https://sca.aliyun.com/docs/2023/user-guide/sentinel/advanced-guide/#%E6%9B%B4%E5%A4%9A%E9%85%8D%E7%BD%AE%E9%A1%B9
*/
@PostConstruct
public void init() {
System.out.println("Load Sentinel Rules start!");
List flowRules = new ArrayList();
FlowRule flowRule = new FlowRule();
flowRule.setResource("GET:https://httpbin.org/get");
flowRule.setCount(1);
flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
flowRule.setStrategy(RuleConstant.STRATEGY_DIRECT);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
List degradeRules = new ArrayList();
DegradeRule degradeRule1 = new DegradeRule();
degradeRule1.setResource("GET:https://httpbin.org/status/500");
degradeRule1.setCount(1);
degradeRule1.setMinRequestAmount(1);
degradeRule1.setTimeWindow(30);
degradeRule1.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
degradeRule1.setLimitApp("default");
degradeRules.add(degradeRule1);
DegradeRule degradeRule2 = new DegradeRule();
degradeRule2.setResource("GET:https://httpbin.org/delay/3");
degradeRule2.setCount(1);
degradeRule2.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule2.setSlowRatioThreshold(0.1);
degradeRule2.setMinRequestAmount(1);
degradeRule2.setTimeWindow(30);
degradeRule2.setLimitApp("default");
degradeRules.add(degradeRule2);
DegradeRuleManager.loadRules(degradeRules);
System.out.println("Load Sentinel Rules end!");
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/main/java/com/alibaba/cloud/examples/controller/TestController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.controller;
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;
/**
* @author raozihao
* @author Steve
*/
@RestController
public class TestController {
@Autowired
RestTemplate restTemplate;
@GetMapping("/exp")
public String exp() {
return restTemplate.getForObject("https://httpbin.org/status/500", String.class);
}
@GetMapping("/rt")
public String rt() {
return restTemplate.getForObject("https://httpbin.org/delay/3", String.class);
}
@GetMapping("/get")
public String get() {
return restTemplate.getForObject("https://httpbin.org/get", String.class);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/main/resources/application.yml
================================================
#
# Copyright 2023-2024 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
server:
port: 18088
spring:
application:
name: sentinel-resttemplate-example
cloud:
sentinel:
transport:
dashboard: localhost:8080
eager: true
# Don't support run in jar by using configuration file method now, refer to https://github.com/alibaba/spring-cloud-alibaba/issues/3033
# cloud:
# sentinel:
# datasource:
# ds1.file:
# file: "classpath: degraderule.json"
# ruleType: "degrade"
# dataType: "json"
# ds2.file:
# file: "classpath: flowrule.json"
# ruleType: "flow"
# dataType: "json"
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/main/resources/degraderule.json
================================================
[
{
"resource": "GET:https://httpbin.org/status/500",
"count": 1,
"grade": 2,
"minRequestAmount": 1,
"timeWindow": 30
},
{
"resource": "GET:https://httpbin.org/delay/3",
"count": 1,
"grade": 0,
"slowRatioThreshold": 0.1,
"minRequestAmount": 1,
"timeWindow": 30
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/main/resources/flowrule.json
================================================
[
{
"resource": "GET:https://httpbin.org/get",
"controlBehavior": 0,
"count": 1,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-resttemplate-example/src/test/java/com/alibaba/cloud/examples/RestTemplateApplicationTest.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
* Test {@link RestTemplateApplication}.
*
* @author wangliang181230
*/
@Disabled("For debugging")
public class RestTemplateApplicationTest {
/**
* Please run this test after execute `mvn clean install -Pnative -e` .
*
* @throws Exception the exception
*/
@Test
public void runWithSpringAotModeAfterProcessAot() throws Exception {
// Enable spring-aot-mode
System.setProperty("spring.aot.enabled", "true");
// Start the application
RestTemplateApplication.main(new String[0]);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0sentinel-spring-cloud-gateway-exampleSpring Cloud Starter Alibaba Sentinel x Gateway ExampleExample demonstrating how to use sentinel with spring cloud gatewayjarcom.alibaba.cloudspring-cloud-starter-alibaba-sentinelorg.springframework.bootspring-boot-starter-webfluxorg.springframework.bootspring-boot-starter-actuatororg.springframework.cloudspring-cloud-starter-gateway-server-webfluxcom.alibaba.cloudspring-cloud-alibaba-sentinel-gatewaycom.alibaba.cspsentinel-datasource-extensionorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/java/com/alibaba/cloud/examples/MySCGConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import reactor.core.publisher.Mono;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
/**
* @author Jim
*/
@Configuration
public class MySCGConfiguration {
@Bean
public BlockRequestHandler blockRequestHandler() {
return new BlockRequestHandler() {
@Override
public Mono handleRequest(ServerWebExchange exchange,
Throwable t) {
return ServerResponse.status(444).contentType(MediaType.APPLICATION_JSON)
.body(fromValue("SCS Sentinel block"));
}
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/java/com/alibaba/cloud/examples/RulesWebFluxController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.List;
import java.util.Set;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
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.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import reactor.core.publisher.Mono;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Jim
*/
@RestController
public class RulesWebFluxController {
@GetMapping("/api")
public Mono> apiRules() {
return Mono.just(GatewayApiDefinitionManager.getApiDefinitions());
}
@GetMapping("/gateway")
public Mono> apiGateway() {
return Mono.just(GatewayRuleManager.getRules());
}
@GetMapping("/flow")
public Mono> apiFlow() {
return Mono.just(FlowRuleManager.getRules());
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/java/com/alibaba/cloud/examples/SentinelSpringCloudGatewayApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author Jim
*/
@SpringBootApplication
public class SentinelSpringCloudGatewayApplication {
public static void main(String[] args) {
// GatewayCallbackManager.setRequestOriginParser(s -> "123");
SpringApplication.run(SentinelSpringCloudGatewayApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/resources/api.json
================================================
[
{
"apiName": "some_customized_api",
"predicateItems": [
{
"pattern": "/product/baz"
},
{
"pattern": "/product/foo/**",
"matchStrategy": 1
},
{
"items": [
{
"pattern": "/spring-cloud/**"
},
{
"pattern": "/spring-cloud-alibaba/**"
}
]
}
]
},
{
"apiName": "another_customized_api",
"predicateItems": [
{
"pattern": "/ahas"
}
]
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/resources/application.yaml
================================================
#
# Copyright 2023-2024 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
server:
port: 18085
spring:
application:
name: sentinel-spring-cloud-gateway
cloud:
gateway:
enabled: true
discovery:
locator:
lower-case-service-id: true
routes:
# Add your routes here.
- id: aliyun_route
uri: https://www.aliyun.com/
predicates:
- Path=/product/**
- id: httpbin_route
uri: https://httpbin.org
predicates:
- Path=/httpbin/**
filters:
- RewritePath=/httpbin/(?.*), /$\{segment}
sentinel:
datasource.ds2.file:
file: "classpath: gateway.json"
ruleType: gw-flow
datasource.ds1.file:
file: "classpath: api.json"
ruleType: gw-api-group
transport:
dashboard: localhost:8080
eager: true
filter:
enabled: true
scg.fallback:
mode: response
response-status: 444
response-body: 1234
scg:
order: -100
management:
endpoints:
web:
exposure:
include: "*"
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-spring-cloud-gateway-example/src/main/resources/gateway.json
================================================
[
{
"resource": "some_customized_api",
"count": 1
},
{
"resource": "httpbin_route",
"count": 0,
"paramItem": {
"parseStrategy": 2,
"fieldName": "Spring-Cloud-Alibaba"
}
},
{
"resource": "httpbin_route",
"count": 0,
"paramItem": {
"parseStrategy": 3,
"fieldName": "name"
}
}
]
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-webflux-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0sentinel-webflux-exampleSpring Cloud Starter Alibaba Sentinel x WebFlux ExampleExample demonstrating how to use sentinel with webfluxjarcom.alibaba.cloudspring-cloud-starter-alibaba-sentinelorg.springframework.bootspring-boot-starter-webfluxorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-webflux-example/src/main/java/com/alibaba/cloud/examples/MyConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.Collections;
import com.alibaba.cloud.circuitbreaker.sentinel.ReactiveSentinelCircuitBreakerFactory;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelConfigBuilder;
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
/**
* @author Jim
*/
@Configuration
public class MyConfiguration {
@Bean
public BlockRequestHandler blockRequestHandler() {
return new BlockRequestHandler() {
@Override
public Mono handleRequest(ServerWebExchange exchange,
Throwable t) {
return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
.contentType(MediaType.APPLICATION_JSON).body(fromValue("block"));
}
};
}
@Bean
public Customizer slowCustomizer() {
return factory -> {
factory.configure(builder -> builder.rules(Collections.singletonList(
new DegradeRule("slow_mono").setGrade(RuleConstant.DEGRADE_GRADE_RT)
.setCount(100).setTimeWindow(5))),
"slow_mono");
factory.configure(builder -> builder.rules(Collections.singletonList(
new DegradeRule("slow_flux").setGrade(RuleConstant.DEGRADE_GRADE_RT)
.setCount(100).setTimeWindow(5))),
"slow_flux");
factory.configureDefault(id -> new SentinelConfigBuilder().resourceName(id)
.rules(Collections.singletonList(new DegradeRule(id)
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
.setCount(0.5).setTimeWindow(10)))
.build());
};
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-webflux-example/src/main/java/com/alibaba/cloud/examples/SentinelWebFluxApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author Jim
*/
@SpringBootApplication
public class SentinelWebFluxApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelWebFluxApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-webflux-example/src/main/java/com/alibaba/cloud/examples/SentinelWebFluxController.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
/**
* @author Jim
*/
@RestController
public class SentinelWebFluxController {
@Autowired
private ReactiveCircuitBreakerFactory circuitBreakerFactory;
@GetMapping("/mono")
public Mono mono() {
return Mono.just("simple string")
// transform the publisher here.
.transform(new SentinelReactorTransformer<>("mono"));
}
@GetMapping("/test")
public Mono test() {
return Mono.just("simple string")
// transform the publisher here.
.transform(new SentinelReactorTransformer<>("test"));
}
@GetMapping("/flux")
public Flux flux() {
return Flux.fromArray(new String[] { "a", "b", "c" })
// transform the publisher here.
.transform(new SentinelReactorTransformer<>("flux"));
}
@GetMapping("/cbSlow")
public Mono cbSlow() {
int delaySecs = 2;
return WebClient.builder().baseUrl("http://httpbin.org/").build().get()
.uri("/delay/" + delaySecs).retrieve().bodyToMono(String.class)
.transform(it -> circuitBreakerFactory.create("slow_mono").run(it, t -> {
t.printStackTrace();
return Mono.just("fallback");
}));
}
@GetMapping("/cbError")
public Mono cbError() {
String code = "500";
return WebClient.builder().baseUrl("http://httpbin.org/").build().get()
.uri("/status/" + code).retrieve().bodyToMono(String.class)
.transform(it -> circuitBreakerFactory.create("cbError").run(it, t -> {
t.printStackTrace();
return Mono.just("fallback");
}));
}
}
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-webflux-example/src/main/resources/application.yml
================================================
#
# Copyright 2023-2024 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
server:
port: 18084
spring:
application:
name: sentinel-webflux-example
cloud:
sentinel:
transport:
dashboard: localhost:8080
eager: true
datasource:
ds1:
file:
file: classpath:flowrule.json
data-type: json
rule-type: flow
management:
endpoints:
web:
exposure:
include=*:
================================================
FILE: spring-cloud-alibaba-examples/sentinel-example/sentinel-webflux-example/src/main/resources/flowrule.json
================================================
[
{
"resource": "/mono",
"controlBehavior": 0,
"count": 0,
"grade": 1,
"limitApp": "default",
"strategy": 0
},
{
"resource": "/flux",
"controlBehavior": 0,
"count": 0,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/node-service.js
================================================
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var http = require('http');
var url = require("url");
var path = require('path');
// 创建server
var server = http.createServer(function(req, res) {
// 获得请求的路径
var pathname = url.parse(req.url).pathname;
res.writeHead(200, { 'Content-Type' : 'application/json; charset=utf-8' });
// 访问http://localhost:8060/,将会返回{"index":"欢迎来到首页"}
if (pathname === '/') {
res.end(JSON.stringify({ "index" : "欢迎来到首页" }));
}
// 访问http://localhost:8060/health,将会返回{"status":"UP"}
else if (pathname === '/health.json') {
res.end(JSON.stringify({ "status" : "UP" }));
}
// 其他情况返回404
else {
res.end("404");
}
});
// 创建监听,并打印日志
server.listen(8060, function() {
console.log('listening on localhost:8060');
});
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/readme-zh.md
================================================
# Spring Cloud Alibaba Sidecar Example
## 项目说明
本项目演示如何使用 Nacos + Spring Cloud Alibaba Sidecar 完成 异构语言微服务的接入。
[Spring Cloud Alibaba Sidecar](https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/zh-cn/index.html#_spring_cloud_alibaba_sidecar) 是一个用来快速完美整合 Spring Cloud 与 异构语言微服务 的框架
## 准备工作
### 下载并启动 Nacos
**在接入 Sidecar 之前,首先需要启动 Nacos服务器。**
1. 下载[Nacos二进制文件](https://github.com/alibaba/nacos/releases/download/2.1.0/nacos-server-2.1.0.zip) 并解压
2. 启动 Nacos Server
下载解压后 我们需要进入到 bin 目录启动 nacos 服务, 一定不要双击启动,双击默认会以集群方式启动,我们以单机方式启动。
```bash
startup.cmd -m standalone
```
3. 登录 Nacos
我们来到浏览器 输入localhost:8848/nacos 可以看到Nacos的运行的界面
用户名和密码都是 `nacos`
## 简单示例
本文以Nacos作为注册中心为例,Sidecar接入一个非Java语言的服务。
### Step1: 引入依赖
修改 `pom.xml` 文件,引入 Spring Cloud Alibaba Sidecar Starter。
```xml
org.springframework.cloudspring-cloud-starter-gateway-server-webfluxcom.alibaba.cloudspring-cloud-starter-alibaba-sidecarcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery
```
### Step2: 配置 Sidecar 相关信息
然后在项目的application.yml 文件中指定以下配置
```yaml
server:
port: 8070
spring:
cloud:
nacos:
username: nacos
password: nacos
discovery:
server-addr: 127.0.0.1:8848
group: test
gateway:
discovery:
locator:
enabled: true
application:
name: node-service
# sidecar 相关的配置
sidecar:
# 异构微服务的IP
ip: 127.0.0.1
# 异构微服务的端口
port: 8060
# 异构微服务的健康检查URL(这里不配置的话,默认会认为是UP)
health-check-url: http://localhost:8060/health.json
# springboot actuator监控相关
management:
endpoint:
health:
show-details: always
```
注意:这里的 localhost:8060,是我本机起了一个nginx 代理了这个health.json的请求。在实际使用过程中可以是任意的REST服务,只需要返回正确的JSON格式的健康检测数据即可。
```json
{
"status": "DOWN"
}
```
### Step3: 启动应用
之后分别启动 Sidecar 服务、本地异构服务。
IDE 直接启动:找到主类 `com.alibaba.cloud.sidecar.DemoApplication`,执行 main 方法启动应用。
注意:本文是以 `spring-cloud-alibaba-sidecar-nacos-example`项目为例,所以启动的是它下面的`DemoApplication`启动类。

### Step4: 查看服务注册情况

### Step4: 访问异构服务
完成上面4步,我们发现对应的服务`node-service`已经成功注册到了注册中心。此时,这个服务已经成功的融入到了Spring Cloud 微服务的怀抱。对于Spring Cloud 微服务而言,访问它跟访问其它的Java微服务没有任何的区别。
而这,也正是 Spring Cloud Alibaba Sidecar的魅力所在。接下来,我们将继续演示怎样访问这个服务。
浏览器访问
http://127.0.0.1:8070/node-service/health.json
能调通则说明整合成功。

## More
如果您对 spring cloud starter alibaba sidecar 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/readme.md
================================================
# Spring Cloud Alibaba Sidecar Example
## Project Instruction
This project demonstrates how to use `Nacos + Spring Cloud Alibaba Sidecar` to access heterogeneous language microservices.
[Spring Cloud Alibaba Sidecar](https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/zh-cn/index.html#_spring_cloud_alibaba_sidecar) is a framework for fast and seamless integration of Spring Cloud with heterogeneous language microservices.
## Preparation
### Download and Startup Nacos
**You should startup Nacos Server before using Sidecar**
1. Download [Nacos](https://archive.apache.org/dist/rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip) and unzip it.
2. Startup Name Server
```bash
startup.cmd -m standalone
```
3. Sign in Nacos
Open you browser then input `localhost:8848/nacos` ,you can see the Nacos dashboard ui .
The default username and password are `nacos`
## Simple example
In this paper, Sidecar accesses a non-Java language service using Nacos as a registry as an example.
### Step1: Declare dependency
Add dependency spring-cloud-starter-alibaba-sidecar to the `pom.xml` file in your Sidecar project.
```xml
org.springframework.cloudspring-cloud-starter-gateway-server-webfluxcom.alibaba.cloudspring-cloud-starter-alibaba-sidecarcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery
```
### Step2: Configure sidecar
Then add necessary configurations to file `/src/main/resources/application.yml`.
```yaml
server:
port: 8070
spring:
cloud:
nacos:
username: nacos
password: nacos
discovery:
server-addr: 127.0.0.1:8848
group: test
gateway:
discovery:
locator:
enabled: true
application:
name: node-service
sidecar:
# heterogeneous service‘s ip
ip: 127.0.0.1
# heterogeneous service's port
port: 8060
# heterogeneous service's health check URL
health-check-url: http://localhost:8060/health.json
```
Note: `localhost:8060` here, is my local machine started a nginx proxy for this `health.json` request. In actual use it can be any REST service, just need to return the correct JSON format health detection data.
```json
{
"status": "DOWN"
}
```
### Step3: Start Application
After that, start the `Sidecar` service and the local heterogeneous service respectively.
Start in IDE: Find main class `com.alibaba.cloud.sidecar.DemoApplication`, and execute the main method.
Note: This article takes the `spring-cloud-alibaba-sidecar-nacos-example` project as an example, so it starts the `DemoApplication` startup class under it.

### Step4: View service registration

### Step4: Accessing services
After completing the above 4 steps, we find that the corresponding service `node-service` has been successfully registered to the registry. At this point, the service has been successfully integrated into the Spring Cloud microservice. For Spring Cloud microservices, accessing it is no different than accessing any other Java microservice.
This is where the beauty of Spring Cloud Alibaba Sidecar comes in. Next, we will continue to demonstrate how to access this service.
Browser Access below address:
http://127.0.0.1:8070/node-service/health.json
If you see the following message, the access was successful.

## More
If you have any ideas or suggestions for `Spring Cloud Alibaba Sidecar`, please don't hesitate to tell us by submitting github issues.
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-consul-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0spring-cloud-alibaba-sidecar-consul-exampleSpring Cloud Starter Alibaba Sidecar x Consul ExampleExample demonstrating how to use Spring Cloud Alibaba Sidecar with consuljarcom.alibaba.cloudspring-cloud-starter-alibaba-sidecarcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-consul-discoveryorg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-testtestorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-consul-example/src/main/java/com/alibaba/cloud/sidecar/DemoApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.sidecar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
@SpringBootApplication
@LoadBalancerClients({
@LoadBalancerClient("node-service")
})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-consul-example/src/main/resources/application.yml
================================================
server:
port: 8070
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
consul:
host: localhost
port: 8500
application:
name: node-service
sidecar:
# 异构微服务的IP
ip: 127.0.0.1
# 异构微服务的端口
port: 8060
# 异构微服务的健康检查URL
health-check-url: http://localhost:8060/health.json
management:
endpoint:
health:
show-details: always
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-example/pom.xml
================================================
com.alibaba.cloudspring-cloud-alibaba-examples${revision}../../pom.xml4.0.0spring-cloud-alibaba-sidecar-nacos-exampleSpring Cloud Starter Alibaba Sidecar x Nacos ExampleExample demonstrating how to use Spring Cloud Alibaba Sidecar with nacosjarorg.springframework.bootspring-boot-starter-actuatororg.springframework.cloudspring-cloud-starter-gateway-server-webfluxcom.alibaba.cloudspring-cloud-starter-alibaba-sidecarcom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloudspring-cloud-starter-loadbalancerorg.springframework.bootspring-boot-starter-testtestorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-example/src/main/java/com/alibaba/cloud/sidecar/DemoApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.sidecar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
@SpringBootApplication
@LoadBalancerClients({
@LoadBalancerClient("node-service")
})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-example/src/main/resources/application.yml
================================================
server:
port: 8070
spring:
cloud:
nacos:
username: 'nacos'
password: 'nacos'
discovery:
server-addr: 127.0.0.1:8848
group: test
gateway:
discovery:
locator:
enabled: true
loadbalancer:
nacos:
enabled: true
ribbon:
enabled: false
application:
name: node-service
sidecar:
# 异构微服务的IP
ip: 127.0.0.1
# 异构微服务的端口
port: 8060
# 异构微服务的健康检查URL
#health-check-url: http://localhost:8060/health.json
management:
endpoint:
health:
show-details: always
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-bus-rocketmq-example/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../pom.xml4.0.0spring-cloud-bus-rocketmq-exampleSpring Cloud Starter Bus Alibaba RocketMQ ExampleExample demonstrating how to use Spring Cloud Bus RocketMQjarcom.alibaba.cloudspring-cloud-starter-bus-rocketmqorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-bus-rocketmq-example/src/main/java/com/alibaba/cloud/examples/rocketmq/RocketMQBusApplication.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.rocketmq;
import tools.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.bus.event.AckRemoteApplicationEvent;
import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* RocketMQ Bus Spring Application.
*
* @author Mercy
* @since 0.2.1
*/
@RestController
@EnableAutoConfiguration
@RemoteApplicationEventScan(basePackages = "com.alibaba.cloud.examples.rocketmq")
public class RocketMQBusApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(RocketMQBusApplication.class)
.properties("server.port=0") // Random server port
.properties("management.endpoints.web.exposure.include=*") // exposure
// includes
// all
.properties("spring.cloud.bus.trace.enabled=true") // Enable trace
.run(args);
}
@Autowired
private ApplicationEventPublisher publisher;
@Value("${spring.cloud.bus.id}")
private String originService;
@Value("${server.port}")
private int localServerPort;
@Autowired
private ObjectMapper objectMapper;
/**
* Publish the {@link UserRemoteApplicationEvent}.
* @param name the user name
* @param destination the destination
* @return If published
*/
@GetMapping("/bus/event/publish/user")
public boolean publish(@RequestParam String name,
@RequestParam(required = false) String destination) {
User user = new User();
user.setId(System.currentTimeMillis());
user.setName(name);
publisher.publishEvent(
new UserRemoteApplicationEvent(this, user, originService, destination));
return true;
}
/**
* Listener on the {@link UserRemoteApplicationEvent}.
* @param event {@link UserRemoteApplicationEvent}
*/
@EventListener
public void onEvent(UserRemoteApplicationEvent event) {
System.out.printf("Server [port : %d] listeners on %s\n", localServerPort,
event.getUser());
}
@EventListener
public void onAckEvent(AckRemoteApplicationEvent event) {
System.out.printf("Server [port : %d] listeners on %s\n", localServerPort,
objectMapper.writeValueAsString(event));
}
}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-bus-rocketmq-example/src/main/java/com/alibaba/cloud/examples/rocketmq/User.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.rocketmq;
/**
* User Domain.
*
* @author Mercy
* @since 0.2.1
*/
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" + "id=" + id + ", name='" + name + '\'' + '}';
}
}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-bus-rocketmq-example/src/main/java/com/alibaba/cloud/examples/rocketmq/UserRemoteApplicationEvent.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.rocketmq;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
/**
* {@link User} {@link RemoteApplicationEvent}.
*
* @author Mercy
* @since 0.2.1
*/
public class UserRemoteApplicationEvent extends RemoteApplicationEvent {
private User user;
public UserRemoteApplicationEvent() {
}
public UserRemoteApplicationEvent(Object source, User user, String originService,
String destinationService) {
super(source, originService, DEFAULT_DESTINATION_FACTORY.getDestination(originService));
this.user = user;
}
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-bus-rocketmq-example/src/main/resources/application.properties
================================================
spring.application.name=spring-cloud-bus-rocketmq-example
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
server.port=8080
spring.cloud.bus.id=${spring.application.name}:${server.port}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/README-en.md
================================================
# Spring Cloud Alibaba Scheduling Example
## Project description
Spring Cloud Alibaba Scheduling provides a timing task scheduling capability based on Spring Scheduling, supporting distributed scenarios for timing task scheduling. It offers a quick integration solution for timing task scheduling services in distributed scenarios.
The current offering is based on the open-source ShedLock for distributed lock acquisition, along with Alibaba Cloud's SchedulerX service [quick start](https://sca.aliyun.com/en/docs/2023/user-guide/schedulerx/quick-start/), Subsequent releases will provide access to more open-source solutions implementations.
## Project dependencies
### Access `spring-cloud-starter-alibaba-schedulerx`
Add the following dependencies to the project `pom.xml`:
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-schedulerx
```
## Project config description
In the Example project, two types of integration configuration modes are provided for `shedlock` and `schedulerx`, Select the required access mode configuration file in `application.yaml`, the example defaults to the shedlock solution.
### Solution 1. Distributed shedlock integration configuration
Edit the following configuration to the `application-schedulerx.yml`:
```yaml
spring:
cloud:
scheduling:
# Distributed mode: shedlock, schedulerx
# Set config value: shedlock
distributed-mode: shedlock
datasource:
driver-class: com.mysql.cj.jdbc.Driver
url: {jdbc_url}
username: {jdbc.username}
password: {jdbc.password}
```
You should replace `{jdbc_url}`,`{jdbc.username}`, and `{jdbc.password}` with your actual database connection information.
>️ Precautions:If there's no database instance can be used, please create a database instance first.
### Solution 2. Alibaba Cloud's SchedulerX integration configuration
Edit the following configuration to the `application-schedulerx.yml`:
```yaml
spring:
cloud:
scheduling:
# Distributed mode: shedlock, schedulerx
# Set config value: schedulerx
distributed-mode: schedulerx
schedulerx:
# This configuration is required, Please get it from aliyun schedulerx console
endpoint: acm.aliyun.com
namespace: aad167f6-xxxx-xxxx-xxxx-xxxxxxxxx
groupId: xxxxx
appKey: PZm1XXXXXXXXXXXX
# Optional config, if you need to sync task to schedulerx
# task-sync: true
# region-id: public
# aliyun-access-key: XXXXXXXXXXXX
# aliyun-secret-key: XXXXXXXXXXXX
# task-model-default: standalone
```
On Alibaba Cloud service, each account has be granted a free quota for schedulerx. For detailed instructions on how to configure and use cloud product integrations, please refer to the respective product documentation. Refer to: [SchedulerX Spring Task](https://www.alibabacloud.com/help/en/schedulerx/user-guide/spring-jobs)
## Start application
After completing the above selection and configuration, simply run the `ScheduleApplication` class in Example to start the application. The `SimpleJob` class in this example project includes two Spring scheduled tasks that run every minute. Upon starting, you can expect to see the following logs:
```text
2024-05-17T11:20:59.981+08:00 INFO 66613 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-17 11:20:59 do job1...
2024-05-17T11:20:59.985+08:00 INFO 66613 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-1] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-17 11:20:59 do job2...
```
### Distributed running verification
Create two application launch configurations in IDEA, each with the startup parameter `--server.port={port}` to start the corresponding application processes. The example project defaults to using `shedlock`,
We can observe that `job1` will be triggered by both applications, whereas `job2` which has been annotated with `@SchedulerLock` will only be triggered in one application at the same time.

- ScheduleApplication-1, startup parameter: `--server.port=18080`, application logs:
```text
2024-05-20T14:02:00.003+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:02:00 do job1...
2024-05-20T14:03:00.008+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:03:00 do job1...
2024-05-20T14:03:00.008+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-1] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:03:00 do job2...
2024-05-20T14:04:00.006+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-3] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:04:00 do job1...
2024-05-20T14:04:00.010+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-2] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:04:00 do job2...
2024-05-20T14:05:00.003+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-5] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:05:00 do job1...
```
- ScheduleApplication-2, startup parameter: `--server.port=18081`, application logs:
```text
2024-05-20T14:02:00.003+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:02:00 do job1...
2024-05-20T14:02:00.008+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-3] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:02:00 do job2...
2024-05-20T14:03:00.004+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-5] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:03:00 do job1...
2024-05-20T14:04:00.006+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-3] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:04:00 do job1...
2024-05-20T14:05:00.004+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-2] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:05:00 do job1...
2024-05-20T14:05:00.007+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:05:00 do job2...
```
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/README.md
================================================
# Spring Cloud Alibaba Scheduling Example
## 项目说明
Spring Cloud Alibaba Scheduling 提供了基于 Spring Scheduling 的定时任务调度能力,支持分布式场景下的定时任务调度,为分布式场景下的定时任务调度服务提供快速接入方案。
目前提供基于开源shedlock分布式抢锁模式,以及阿里云上SchedulerX服务的 [快速接入](https://sca.aliyun.com/docs/2023/user-guide/schedulerx/quick-start/) ,后续将提供更多实现的开源方案接入。
## 应用依赖
### 接入 `spring-cloud-starter-alibaba-schedulerx`
在项目 pom.xml 中加入以下依赖:
```xml
com.alibaba.cloudspring-cloud-starter-alibaba-schedulerx
```
## 配置说明
在Example工程中提供shedlock和schedulerx的两种接入配置模式(***二选一***),在`application.yaml`中选择需要的接入模式配置文件,案例中默认采用开源的shedlock方案。
### 方案一、分布式shedlock接入配置说明
在 application-schedulerx.yml 配置文件中修改以下配置:
```yaml
spring:
cloud:
scheduling:
# Distributed mode: shedlock, schedulerx
# Set config value: shedlock
distributed-mode: shedlock
datasource:
driver-class: com.mysql.cj.jdbc.Driver
url: {jdbc_url}
username: {jdbc.username}
password: {jdbc.password}
```
使用时请需要替换`{jdbc_url}`、`{jdbc.username}`、`{jdbc.password}`为实际自有的数据库连接信息。
>️ 注意:如未创建数据库,请先手动创建数据实例。
### 方案二、云产品SchedulerX接入配置说明
在 application-schedulerx.yml 配置文件中修改以下配置:
```yaml
spring:
cloud:
scheduling:
# Distributed mode: shedlock, schedulerx
# Set config value: schedulerx
distributed-mode: schedulerx
schedulerx:
# This configuration is required, Please get it from aliyun schedulerx console
endpoint: acm.aliyun.com
namespace: aad167f6-xxxx-xxxx-xxxx-xxxxxxxxx
groupId: xxxxx
appKey: PZm1XXXXXXXXXXXX
# Optional config, if you need to sync task to schedulerx
# task-sync: true
# region-id: public
# aliyun-access-key: XXXXXXXXXXXX
# aliyun-secret-key: XXXXXXXXXXXX
# task-model-default: standalone
```
阿里云上产品每个用户开通后都会有免费额度,详细云上产品接入配置使用说明,请参考:[阿里云SchedulerX Spring定时任务](https://help.aliyun.com/zh/schedulerx/user-guide/spring-jobs)
## 启动应用
在完成上述接入选择和配置后,直接运行Example中的 `ScheduleApplication`类即可启动运行。本案例工程中的`SimpleJob`类包含了两个每分钟执行一次的Spring定时任务,启动后可得到如下日志:
```text
2024-05-17T11:20:59.981+08:00 INFO 66613 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-17 11:20:59 do job1...
2024-05-17T11:20:59.985+08:00 INFO 66613 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-1] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-17 11:20:59 do job2...
```
### 分布式运行验证
在IDEA环境中创建两个应用启动项,各自分别配置启动参数`--server.port={应用端口}`,启动相应的应用进程。案例工程默认采用`shedlock`,
我们可以直接看到`job1`两个应用都会同时触发,而`job2`添加了`@SchedulerLock`注解则会同一时间点只会在一个应用进程中执行。

- ScheduleApplication-1,启动参数:`--server.port=18080`,定时任务运行日志如下:
```text
2024-05-20T14:02:00.003+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:02:00 do job1...
2024-05-20T14:03:00.008+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:03:00 do job1...
2024-05-20T14:03:00.008+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-1] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:03:00 do job2...
2024-05-20T14:04:00.006+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-3] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:04:00 do job1...
2024-05-20T14:04:00.010+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-2] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:04:00 do job2...
2024-05-20T14:05:00.003+08:00 INFO 80520 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-5] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:05:00 do job1...
```
- ScheduleApplication-2,启动参数:`--server.port=18081`,定时任务运行日志如下:
```text
2024-05-20T14:02:00.003+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:02:00 do job1...
2024-05-20T14:02:00.008+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-3] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:02:00 do job2...
2024-05-20T14:03:00.004+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-5] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:03:00 do job1...
2024-05-20T14:04:00.006+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-3] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:04:00 do job1...
2024-05-20T14:05:00.004+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-2] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:05:00 do job1...
2024-05-20T14:05:00.007+08:00 INFO 80596 --- [spring-cloud-alibaba-schedule-example] [ sca-schedule-4] c.a.c.examples.schedule.job.SimpleJob : time=2024-05-20 14:05:00 do job2...
```
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/pom.xml
================================================
spring-cloud-alibaba-examplescom.alibaba.cloud${revision}../pom.xml4.0.0spring-cloud-scheduling-exampleSpring Cloud Starter Alibaba Scheduling ExampleExample demonstrating how to use Spring Cloud Schedulejarcom.alibaba.cloudspring-cloud-starter-alibaba-schedulerxorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-jdbccom.mysqlmysql-connector-jorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}true
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/src/main/java/com/alibaba/cloud/examples/schedule/ScheduleApplication.java
================================================
/*
* Copyright 2024-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.schedule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* ScheduleApplication.
*
* @author yaohui
*/
@SpringBootApplication
@EnableScheduling
public class ScheduleApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleApplication.class, args);
}
}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/src/main/java/com/alibaba/cloud/examples/schedule/job/SimpleJob.java
================================================
/*
* Copyright 2024-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples.schedule.job;
import java.util.concurrent.TimeUnit;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author yaohui
**/
@Component
public class SimpleJob {
private static final Logger logger = LoggerFactory.getLogger(SimpleJob.class);
/**
* run without lock, all instance running at the same time.
*/
@Scheduled(cron = "0 */1 * * * ?")
public void job1() {
logger.info("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job1...");
}
/**
* run with lock, only one instance running at the same time.
*
* @throws InterruptedException interrupted exception
*/
@Scheduled(cron = "0 */1 * * * ?")
@SchedulerLock(name = "lock-job2", lockAtMostFor = "10s")
public void job2() throws InterruptedException {
logger.info("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job2...");
TimeUnit.SECONDS.sleep(1L);
}
}
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/src/main/resources/application-schedulerx.yaml
================================================
spring:
cloud:
scheduling:
# Distributed mode: shedlock, schedulerx
distributed-mode: schedulerx
schedulerx:
# This configuration is required, Please get it from aliyun schedulerx console
endpoint: acm.aliyun.com
namespace: aad167f6-xxxx-xxxx-xxxx-xxxxxxxxx
groupId: xxxxx
appKey: PZm1XXXXXXXXXXXX
# Optional config, if you need to sync task to schedulerx
# task-sync: true
# region-id: public
# aliyun-access-key: XXXXXXXXXXXX
# aliyun-secret-key: XXXXXXXXXXXX
# task-model-default: standalone
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/src/main/resources/application-shedlock.yaml
================================================
spring:
cloud:
scheduling:
# Distributed mode: shedlock, schedulerx
distributed-mode: shedlock
datasource:
driver-class: com.mysql.cj.jdbc.Driver
# Change to your database jdbc url value
url: jdbc:mysql://127.0.0.1:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
# Change to your database username value
username: root
# Change to your database password value
password: 123456
================================================
FILE: spring-cloud-alibaba-examples/spring-cloud-scheduling-example/src/main/resources/application.yaml
================================================
server:
port: 18080
spring:
profiles:
# Select the config file to use, shedlock or schedulerx
active: shedlock
application:
name: spring-cloud-alibaba-schedule-example
# Spring task scheduling config
task:
scheduling:
thread-name-prefix: sca-schedule-
pool:
size: 5
shutdown:
await-termination: true
await-termination-period: 60s
================================================
FILE: spring-cloud-alibaba-starters/pom.xml
================================================
4.0.0com.alibaba.cloudspring-cloud-alibaba${revision}../pom.xmlspring-cloud-alibaba-starterspomSpring Cloud Alibaba StartersSpring Cloud Alibaba Startersspring-alibaba-nacos-configspring-cloud-starter-alibaba-nacos-configspring-cloud-starter-alibaba-nacos-discoveryspring-cloud-starter-alibaba-seataspring-cloud-starter-stream-rocketmqspring-cloud-starter-bus-rocketmqspring-cloud-starter-alibaba-sidecarspring-cloud-circuitbreaker-sentinelspring-cloud-starter-alibaba-sentinelspring-cloud-alibaba-sentinel-datasourcespring-cloud-alibaba-sentinel-gatewayspring-cloud-alibaba-commonsspring-cloud-starter-alibaba-schedulerxorg.jacocojacoco-maven-plugin${jacoco.version}jacoco-initializeprepare-agentjacoco-sitetestreport
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/pom.xml
================================================
4.0.0com.alibaba.cloudspring-cloud-alibaba-starters${revision}../pom.xmlspring-alibaba-nacos-configSpring Alibaba Nacos Configorg.springframework.bootspring-boot-healthprovidedorg.springframework.bootspring-boot-actuator-autoconfiguretrueorg.springframework.bootspring-boot-configuration-processortruecom.alibaba.nacosnacos-clientorg.springframework.bootspring-boot-starter-webtestcom.alibabadruidprovidedorg.springframeworkspring-weborg.springframework.bootspring-boot-starter-testtestorg.slf4jslf4j-apijakarta.annotationjakarta.annotation-api
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigAutoConfiguration.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import com.alibaba.cloud.nacos.annotation.NacosAnnotationProcessor;
import com.alibaba.cloud.nacos.refresh.NacosContextRefresher;
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/**
* @author juven.xuxb
* @author freeman
*/
@Configuration(proxyBeanMethods = false)
@Conditional(NacosConfigEnabledCondition.class)
public class NacosConfigAutoConfiguration {
@Bean
@ConditionalOnMissingBean(value = NacosConfigProperties.class, search = SearchStrategy.CURRENT)
public NacosConfigProperties nacosConfigProperties(ApplicationContext context) {
if (context.getParent() != null && BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context.getParent(),
NacosConfigProperties.class).length > 0) {
return BeanFactoryUtils.beanOfTypeIncludingAncestors(context.getParent(), NacosConfigProperties.class);
}
if (NacosConfigManager.getInstance() == null) { // this should never happen except for some unit tests
return new NacosConfigProperties();
}
else {
return NacosConfigManager.getInstance().getNacosConfigProperties();
}
}
@Bean
public NacosRefreshHistory nacosRefreshHistory() {
return new NacosRefreshHistory();
}
@Bean
public NacosConfigManager nacosConfigManager(NacosConfigProperties nacosConfigProperties) {
return NacosConfigManager.getInstance(nacosConfigProperties);
}
@Bean
public static NacosAnnotationProcessor nacosAnnotationProcessor() {
return new NacosAnnotationProcessor();
}
@Bean
public NacosContextRefresher nacosContextRefresher(NacosConfigManager nacosConfigManager,
NacosRefreshHistory nacosRefreshHistory) {
// Consider that it is not necessary to be compatible with the previous
// configuration
// and use the new configuration if necessary.
return new NacosContextRefresher(nacosConfigManager, nacosRefreshHistory);
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigEnabledCondition.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author shiyiyue
*/
public class NacosConfigEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String prefix = NacosPropertiesPrefixer.getPrefix(context.getEnvironment());
return context.getEnvironment().getProperty(prefix + ".config.enabled", Boolean.class, true);
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigManager.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import java.util.Objects;
import com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureException;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author zkzlx
*/
public class NacosConfigManager {
private static final Logger log = LoggerFactory.getLogger(NacosConfigManager.class);
private static ConfigService service;
private static NacosConfigManager INSTANCE;
private NacosConfigProperties nacosConfigProperties;
public NacosConfigManager(NacosConfigProperties nacosConfigProperties) {
this.nacosConfigProperties = nacosConfigProperties;
}
public static NacosConfigManager getInstance() {
return INSTANCE;
}
public static NacosConfigManager getInstance(NacosConfigProperties properties) {
if (INSTANCE != null) {
return INSTANCE;
}
synchronized (NacosConfigManager.class) {
if (INSTANCE == null) {
INSTANCE = new NacosConfigManager(properties);
INSTANCE.createConfigService(properties);
}
}
return INSTANCE;
}
/**
* Compatible with old design,It will be perfected in the future.
*/
private ConfigService createConfigService(
NacosConfigProperties nacosConfigProperties) {
try {
if (Objects.isNull(service)) {
service = NacosFactory.createConfigService(
nacosConfigProperties.assembleConfigServiceProperties());
}
}
catch (NacosException e) {
log.error(e.getMessage());
throw new NacosConnectionFailureException(
nacosConfigProperties.getServerAddr(), e.getMessage(), e);
}
return service;
}
public ConfigService getConfigService() {
if (Objects.isNull(service)) {
createConfigService(this.nacosConfigProperties);
}
return service;
}
public NacosConfigProperties getNacosConfigProperties() {
return nacosConfigProperties;
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigProperties.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.alibaba.cloud.nacos.utils.PropertySourcesUtils;
import com.alibaba.cloud.nacos.utils.StringUtils;
import com.alibaba.nacos.api.config.ConfigService;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT;
import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_RETRY_TIME;
import static com.alibaba.nacos.api.PropertyKeyConst.ENABLE_REMOTE_SYNC_CONFIG;
import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT;
import static com.alibaba.nacos.api.PropertyKeyConst.MAX_RETRY;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD;
import static com.alibaba.nacos.api.PropertyKeyConst.RAM_ROLE_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
import static com.alibaba.nacos.api.PropertyKeyConst.USERNAME;
/**
* Nacos properties.
*
* @author leijuan
* @author xiaojing
* @author pbting
* @author lyuzb
*/
public class NacosConfigProperties {
/**
* COMMAS , .
*/
public static final String COMMAS = ",";
/**
* SEPARATOR , .
*/
public static final String SEPARATOR = "[,]";
/**
* Nacos default namespace .
*/
public static final String DEFAULT_NAMESPACE = "public";
/**
* Nacos default server and port.
*/
public static final String DEFAULT_ADDRESS = "127.0.0.1:8848";
private static final Pattern PATTERN = Pattern.compile("-(\\w)");
private static final Logger log = LoggerFactory
.getLogger(NacosConfigProperties.class);
@Autowired
@JsonIgnore
private Environment environment;
/**
* nacos config server address.
*/
private String serverAddr;
/**
* the nacos authentication username.
*/
private String username;
/**
* the nacos authentication password.
*/
private String password;
/**
* encode for nacos config content.
*/
private String encode;
/**
* nacos config group, group is config data meta info.
*/
private String group = "DEFAULT_GROUP";
/**
* nacos config dataId prefix.
*/
private String prefix;
/**
* the suffix of nacos config dataId, also the file extension of config content.
*/
private String fileExtension = "properties";
/**
* timeout for get config from nacos.
*/
private int timeout = 3000;
/**
* nacos maximum number of tolerable server reconnection errors.
*/
private String maxRetry;
/**
* nacos get config long poll timeout.
*/
private String configLongPollTimeout;
/**
* nacos get config failure retry time.
*/
private String configRetryTime;
/**
* If you want to pull it yourself when the program starts to get the configuration
* for the first time, and the registered Listener is used for future configuration
* updates, you can keep the original code unchanged, just add the system parameter:
* enableRemoteSyncConfig = "true" ( But there is network overhead); therefore we
* recommend that you use {@link ConfigService#getConfigAndSignListener} directly.
*/
private boolean enableRemoteSyncConfig = false;
/**
* endpoint for Nacos, the domain name of a service, through which the server address
* can be dynamically obtained.
*/
private String endpoint;
/**
* namespace, separation configuration of different environments.
*/
private String namespace;
/**
* access key for namespace.
*/
private String accessKey;
/**
* secret key for namespace.
*/
private String secretKey;
/**
* role name for aliyun ram.
*/
private String ramRoleName;
/**
* context path for nacos config server.
*/
private String contextPath;
/**
* nacos config cluster name.
*/
private String clusterName;
/**
* nacos config dataId name.
*/
private String name;
/**
* a set of shared configurations .e.g:
* spring.cloud.nacos.config.shared-configs[0]=xxx .
*/
private List sharedConfigs;
/**
* a set of extensional configurations .e.g:
* spring.cloud.nacos.config.extension-configs[0]=xxx .
*/
private List extensionConfigs;
/**
* the master switch for refresh configuration, it default opened(true).
*/
private boolean refreshEnabled = true;
@PostConstruct
public void init() {
this.overrideFromEnv();
}
private void overrideFromEnv() {
if (environment == null) {
return;
}
String prefix = NacosPropertiesPrefixer.getPrefix(environment);
if (StringUtils.isEmpty(this.getServerAddr())) {
String serverAddr = environment
.resolvePlaceholders("${" + prefix + ".config.server-addr:}");
if (StringUtils.isEmpty(serverAddr)) {
serverAddr = environment.resolvePlaceholders(
"${" + prefix + ".server-addr:127.0.0.1:8848}");
}
this.setServerAddr(serverAddr);
}
if (StringUtils.isEmpty(this.getUsername())) {
this.setUsername(
environment.resolvePlaceholders("${" + prefix + ".username:}"));
}
if (StringUtils.isEmpty(this.getPassword())) {
this.setPassword(
environment.resolvePlaceholders("${" + prefix + ".password:}"));
}
}
// todo sts support
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getFileExtension() {
return fileExtension;
}
public void setFileExtension(String fileExtension) {
this.fileExtension = fileExtension;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getMaxRetry() {
return maxRetry;
}
public void setMaxRetry(String maxRetry) {
this.maxRetry = maxRetry;
}
public String getConfigLongPollTimeout() {
return configLongPollTimeout;
}
public void setConfigLongPollTimeout(String configLongPollTimeout) {
this.configLongPollTimeout = configLongPollTimeout;
}
public String getConfigRetryTime() {
return configRetryTime;
}
public void setConfigRetryTime(String configRetryTime) {
this.configRetryTime = configRetryTime;
}
public Boolean getEnableRemoteSyncConfig() {
return enableRemoteSyncConfig;
}
public void setEnableRemoteSyncConfig(Boolean enableRemoteSyncConfig) {
this.enableRemoteSyncConfig = enableRemoteSyncConfig;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getRamRoleName() {
return ramRoleName;
}
public void setRamRoleName(String ramRoleName) {
this.ramRoleName = ramRoleName;
}
public String getEncode() {
return encode;
}
public void setEncode(String encode) {
this.encode = encode;
}
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public String getClusterName() {
return clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public List getSharedConfigs() {
return sharedConfigs;
}
public void setSharedConfigs(List sharedConfigs) {
this.sharedConfigs = sharedConfigs;
}
public List getExtensionConfigs() {
return extensionConfigs;
}
public void setExtensionConfigs(List extensionConfigs) {
this.extensionConfigs = extensionConfigs;
}
public boolean isRefreshEnabled() {
return refreshEnabled;
}
public void setRefreshEnabled(boolean refreshEnabled) {
this.refreshEnabled = refreshEnabled;
}
/**
* recommend to use {@link NacosConfigProperties#sharedConfigs} .
* @return string
*/
@Deprecated
@DeprecatedConfigurationProperty(reason = "use spring.config.import instead")
public String getSharedDataids() {
return null == getSharedConfigs() ? null
: getSharedConfigs().stream().map(Config::getDataId)
.collect(Collectors.joining(COMMAS));
}
/**
* recommend to use {@link NacosConfigProperties#sharedConfigs} and not use it at the
* same time .
* @param sharedDataids the dataids for configurable multiple shared configurations ,
* multiple separated by commas .
*/
@Deprecated
public void setSharedDataids(String sharedDataids) {
if (null != sharedDataids && sharedDataids.trim().length() > 0) {
List list = new ArrayList<>();
Stream.of(sharedDataids.split(SEPARATOR))
.forEach(dataId -> list.add(new Config(dataId.trim())));
this.compatibleSharedConfigs(list);
}
}
/**
* Not providing support,the need to refresh is specified by the respective refresh
* configuration and not use it at the same time .
* @return string
*/
@Deprecated
public String getRefreshableDataids() {
return null == getSharedConfigs() ? null
: getSharedConfigs().stream().filter(Config::isRefresh)
.map(Config::getDataId).collect(Collectors.joining(COMMAS));
}
/**
* Not providing support,the need to refresh is specified by the respective refresh
* configuration and not use it at the same time .
* @param refreshableDataids refreshable dataids ,multiple separated by commas .
*/
@Deprecated
public void setRefreshableDataids(String refreshableDataids) {
if (null != refreshableDataids && refreshableDataids.trim().length() > 0) {
List list = new ArrayList<>();
Stream.of(refreshableDataids.split(SEPARATOR)).forEach(
dataId -> list.add(new Config(dataId.trim()).setRefresh(true)));
this.compatibleSharedConfigs(list);
}
}
private void compatibleSharedConfigs(List configList) {
if (null != this.getSharedConfigs()) {
configList.addAll(this.getSharedConfigs());
}
List result = new ArrayList<>();
configList.stream()
.collect(Collectors.groupingBy(cfg -> (cfg.getGroup() + cfg.getDataId()),
LinkedHashMap::new, Collectors.toList()))
.forEach((key, list) -> {
list.stream()
.reduce((a, b) -> new Config(a.getDataId(), a.getGroup(),
a.isRefresh() || (b != null && b.isRefresh())))
.ifPresent(result::add);
});
this.setSharedConfigs(result);
}
/**
* recommend to use
* {@link com.alibaba.cloud.nacos.NacosConfigProperties#extensionConfigs} and not use
* it at the same time .
* @return extensionConfigs
*/
@Deprecated
@DeprecatedConfigurationProperty(reason = "use spring.config.import instead")
public List getExtConfig() {
return this.getExtensionConfigs();
}
@Deprecated
public void setExtConfig(List extConfig) {
this.setExtensionConfigs(extConfig);
}
/**
* recommend to use {@link NacosConfigManager#getConfigService()}.
* @return ConfigService
*/
@Deprecated
public ConfigService configServiceInstance() {
// The following code will be migrated
return NacosConfigManager.getInstance(this).getConfigService();
}
/**
* recommend to use {@link NacosConfigProperties#assembleConfigServiceProperties()}.
* @return ConfigServiceProperties
*/
@Deprecated
public Properties getConfigServiceProperties() {
return this.assembleConfigServiceProperties();
}
/**
* assemble properties for configService. (cause by rename : Remove the interference
* of auto prompts when writing,because autocue is based on get method.
* @return properties
*/
public Properties assembleConfigServiceProperties() {
Properties properties = new Properties();
properties.put(SERVER_ADDR, Objects.toString(this.serverAddr, ""));
properties.put(USERNAME, Objects.toString(this.username, ""));
properties.put(PASSWORD, Objects.toString(this.password, ""));
properties.put(ENCODE, Objects.toString(this.encode, ""));
properties.put(NAMESPACE, this.resolveNamespace());
properties.put(ACCESS_KEY, Objects.toString(this.accessKey, ""));
properties.put(SECRET_KEY, Objects.toString(this.secretKey, ""));
properties.put(RAM_ROLE_NAME, Objects.toString(this.ramRoleName, ""));
properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, ""));
properties.put(MAX_RETRY, Objects.toString(this.maxRetry, ""));
properties.put(CONFIG_LONG_POLL_TIMEOUT,
Objects.toString(this.configLongPollTimeout, ""));
properties.put(CONFIG_RETRY_TIME, Objects.toString(this.configRetryTime, ""));
properties.put(ENABLE_REMOTE_SYNC_CONFIG,
Objects.toString(this.enableRemoteSyncConfig, ""));
String endpoint = Objects.toString(this.endpoint, "");
if (endpoint.contains(":")) {
int index = endpoint.indexOf(":");
properties.put(ENDPOINT, endpoint.substring(0, index));
properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));
}
else {
properties.put(ENDPOINT, endpoint);
}
enrichNacosConfigProperties(properties);
// set default value when serverAddr and endpoint is empty
if (StringUtils.isEmpty(this.serverAddr) && StringUtils.isEmpty(this.endpoint)) {
properties.put(SERVER_ADDR, DEFAULT_ADDRESS);
}
return properties;
}
/**
* refer
* https://github.com/alibaba/spring-cloud-alibaba/issues/2872
* https://github.com/alibaba/spring-cloud-alibaba/issues/2869 .
*/
private String resolveNamespace() {
if (DEFAULT_NAMESPACE.equals(this.namespace)) {
log.info("set nacos config namespace 'public' to ''");
return "";
}
else {
return Objects.toString(this.namespace, "");
}
}
protected void enrichNacosConfigProperties(Properties nacosConfigProperties) {
if (environment == null) {
return;
}
String prefix = NacosPropertiesPrefixer.getPrefix(environment);
Map properties = PropertySourcesUtils
.getSubProperties((ConfigurableEnvironment) environment, prefix + ".config");
properties.forEach((k, v) -> nacosConfigProperties.putIfAbsent(resolveKey(k),
String.valueOf(v)));
}
protected String resolveKey(String key) {
Matcher matcher = PATTERN.matcher(key);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group(1).toUpperCase(Locale.ROOT));
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* refer
* https://github.com/alibaba/spring-cloud-alibaba/issues/4242
* Mask sensitive fields in logs to avoid credential leakage.
*/
private static String mask(String value) {
return (value == null || value.isEmpty()) ? value : "******";
}
@Override
public String toString() {
return "NacosConfigProperties{"
+ "serverAddr='" + serverAddr + '\''
+ ", encode='" + encode + '\''
+ ", group='" + group + '\''
+ ", prefix='" + prefix + '\''
+ ", fileExtension='" + fileExtension + '\''
+ ", timeout=" + timeout
+ ", maxRetry='" + maxRetry + '\''
+ ", configLongPollTimeout='" + configLongPollTimeout + '\''
+ ", configRetryTime='" + configRetryTime + '\''
+ ", enableRemoteSyncConfig=" + enableRemoteSyncConfig
+ ", endpoint='" + endpoint + '\''
+ ", namespace='" + namespace + '\''
+ ", accessKey='" + mask(accessKey) + '\''
+ ", secretKey='" + mask(secretKey) + '\''
+ ", ramRoleName='" + ramRoleName + '\''
+ ", contextPath='" + contextPath + '\''
+ ", clusterName='" + clusterName + '\''
+ ", name='" + name + '\''
+ ", shares=" + sharedConfigs
+ ", extensions=" + extensionConfigs
+ ", refreshEnabled=" + refreshEnabled
+ '}';
}
public static class Config {
/**
* the data id of extended configuration.
*/
private String dataId;
/**
* the group of extended configuration, the default value is DEFAULT_GROUP.
*/
private String group = "DEFAULT_GROUP";
/**
* whether to support dynamic refresh, the default does not support .
*/
private boolean refresh = false;
public Config() {
}
public Config(String dataId) {
this.dataId = dataId;
}
public Config(String dataId, String group) {
this(dataId);
this.group = group;
}
public Config(String dataId, boolean refresh) {
this(dataId);
this.refresh = refresh;
}
public Config(String dataId, String group, boolean refresh) {
this(dataId, group);
this.refresh = refresh;
}
public String getDataId() {
return dataId;
}
public Config setDataId(String dataId) {
this.dataId = dataId;
return this;
}
public String getGroup() {
return group;
}
public Config setGroup(String group) {
this.group = group;
return this;
}
public boolean isRefresh() {
return refresh;
}
public Config setRefresh(boolean refresh) {
this.refresh = refresh;
return this;
}
@Override
public String toString() {
return "Config{" + "dataId='" + dataId + '\'' + ", group='" + group + '\''
+ ", refresh=" + refresh + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Config config = (Config) o;
return refresh == config.refresh && Objects.equals(dataId, config.dataId)
&& Objects.equals(group, config.group);
}
@Override
public int hashCode() {
return Objects.hash(dataId, group, refresh);
}
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosPropertiesPrefixProvider.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
/**
* @author shiyiyue
*/
public interface NacosPropertiesPrefixProvider {
String getPrefix();
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosPropertiesPrefixer.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import java.util.ServiceLoader;
import com.alibaba.cloud.nacos.utils.StringUtils;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;
/**
* @author shiyiyue
*/
public final class NacosPropertiesPrefixer {
/**
* prefix from spi provider.
*/
public static final String PREFIX = getPrefixFromSpi();
private NacosPropertiesPrefixer() {
}
private static String getPrefixFromSpi() {
ServiceLoader load = ServiceLoader.load(NacosPropertiesPrefixProvider.class);
for (NacosPropertiesPrefixProvider provider : load) {
return provider.getPrefix();
}
return "";
}
public static String getPrefix(Environment environment) {
String prefix = "spring.nacos";
String prefixFromProperties = environment.getProperty("spring.nacos.properties.prefix");
if (StringUtils.isBlank(prefixFromProperties)) {
if (StringUtils.isNotBlank(NacosPropertiesPrefixer.PREFIX)) {
prefix = NacosPropertiesPrefixer.PREFIX;
}
}
else {
prefix = prefixFromProperties;
}
if (StringUtils.isNotBlank(prefix) && prefix.endsWith(".")) {
prefix = prefix.substring(0, prefix.length() - 1);
}
return prefix;
}
public static String getPrefix(Binder binder) {
String prefix = "spring.nacos";
BindResult bind = binder.bind("spring.nacos.properties.prefix", String.class);
if (!bind.isBound()) {
if (StringUtils.isNotBlank(NacosPropertiesPrefixer.PREFIX)) {
prefix = NacosPropertiesPrefixer.PREFIX;
}
}
else {
prefix = bind.get();
}
if (StringUtils.isNotBlank(prefix) && prefix.endsWith(".")) {
prefix = prefix.substring(0, prefix.length() - 1);
}
return prefix;
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosPropertySourceRepository.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.cloud.nacos.client.NacosPropertySource;
/**
* @author xiaojing
* @author pbting
*/
public final class NacosPropertySourceRepository {
private final static ConcurrentHashMap NACOS_PROPERTY_SOURCE_REPOSITORY = new ConcurrentHashMap<>();
private NacosPropertySourceRepository() {
}
/**
* @return all nacos properties from application context.
*/
public static List getAll() {
return new ArrayList<>(NACOS_PROPERTY_SOURCE_REPOSITORY.values());
}
/**
* recommend to use {@link NacosPropertySourceRepository#collectNacosPropertySource}.
* @param nacosPropertySource nacosPropertySource
*/
@Deprecated
public static void collectNacosPropertySources(
NacosPropertySource nacosPropertySource) {
NACOS_PROPERTY_SOURCE_REPOSITORY.putIfAbsent(nacosPropertySource.getDataId(),
nacosPropertySource);
}
/**
* recommend to use
* {@link NacosPropertySourceRepository#getNacosPropertySource(java.lang.String, java.lang.String)}.
* @param dataId dataId
* @return NacosPropertySource
*/
@Deprecated
public static NacosPropertySource getNacosPropertySource(String dataId) {
return NACOS_PROPERTY_SOURCE_REPOSITORY.get(dataId);
}
public static void collectNacosPropertySource(
NacosPropertySource nacosPropertySource) {
NACOS_PROPERTY_SOURCE_REPOSITORY
.putIfAbsent(getMapKey(nacosPropertySource.getDataId(),
nacosPropertySource.getGroup()), nacosPropertySource);
}
public static NacosPropertySource getNacosPropertySource(String dataId,
String group) {
return NACOS_PROPERTY_SOURCE_REPOSITORY.get(getMapKey(dataId, group));
}
public static String getMapKey(String dataId, String group) {
return String.join(NacosConfigProperties.COMMAS, String.valueOf(dataId),
String.valueOf(group));
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/AbstractConfigChangeListener.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.util.Map;
import com.alibaba.nacos.api.config.ConfigChangeEvent;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
import com.alibaba.nacos.client.config.impl.ConfigChangeHandler;
public abstract class AbstractConfigChangeListener extends AbstractSharedListener implements TargetRefreshable {
String lastContent;
Object target;
@Override
public Object getTarget() {
return target;
}
@Override
public void setTarget(Object target) {
this.target = target;
}
public AbstractConfigChangeListener(Object target) {
this.target = target;
}
protected void setLastContent(String lastContent) {
this.lastContent = lastContent;
}
@Override
public void innerReceive(String dataId, String group, String configInfo) {
Map data = null;
try {
data = ConfigChangeHandler.getInstance().parseChangeData(lastContent, configInfo, type(dataId));
}
catch (Exception e) {
throw new RuntimeException(e);
}
ConfigChangeEvent event = new ConfigChangeEvent(data);
receiveConfigChange(event);
lastContent = configInfo;
}
private String type(String dataId) {
if (dataId.endsWith(".yml") || dataId.endsWith(".yaml")) {
return "yaml";
}
return "properties";
}
abstract void receiveConfigChange(ConfigChangeEvent event);
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/CustomDateDeserializer.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
public class CustomDateDeserializer extends JsonDeserializer {
private static final long serialVersionUID = 1L;
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public CustomDateDeserializer() {
super();
}
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
String date = node.textValue();
try {
return dateFormat.parse(date);
}
catch (Exception e) {
throw new IOException("Invalid date format");
}
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/JsonUtils.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.io.IOException;
import java.lang.reflect.Type;
import com.alibaba.nacos.api.exception.runtime.NacosDeserializationException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
final class JsonUtils {
private JsonUtils() {
}
static ObjectMapper mapper = new ObjectMapper();
static {
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
/**
* Json string deserialize to Object.
*
* @param json json string
* @param cls class of object
* @param General type
* @return object
* @throws NacosDeserializationException if deserialize failed
*/
public static T toObj(String json, Class cls) {
try {
return mapper.readValue(json, cls);
}
catch (IOException e) {
throw new NacosDeserializationException(cls, e);
}
}
public static T toObj(String json, Type type) {
try {
return mapper.readValue(json, TypeFactory.defaultInstance().constructType(type));
}
catch (IOException e) {
throw new NacosDeserializationException(type, e);
}
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosAnnotationProcessor.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigChangeEvent;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.client.config.common.GroupKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.NotReadablePropertyException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.ReflectionUtils;
public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware {
private NacosConfigManager nacosConfigManager;
private ApplicationContext applicationContext;
private final static Logger log = LoggerFactory
.getLogger(NacosAnnotationProcessor.class);
@Override
public int getOrder() {
return 0;
}
private Map targetListenerMap = new ConcurrentHashMap<>();
private Map> groupKeyCache = new ConcurrentHashMap<>();
private String getGroupKeyContent(String dataId, String group, boolean refreshed) throws Exception {
if (groupKeyCache.containsKey(GroupKey.getKey(dataId, group))) {
return groupKeyCache.get(GroupKey.getKey(dataId, group)).get();
}
synchronized (this) {
if (!groupKeyCache.containsKey(GroupKey.getKey(dataId, group))) {
String content = getNacosConfigManager().getConfigService().getConfig(dataId, group, 5000);
groupKeyCache.put(GroupKey.getKey(dataId, group), new AtomicReference<>(content));
if (!refreshed) {
log.info("[Nacos Config] refreshed is set to false, not listening config for annotation: dataId={}, group={}", dataId,
group);
return content;
}
log.info("[Nacos Config] Listening config for annotation: dataId={}, group={}", dataId,
group);
getNacosConfigManager().getConfigService().addListener(dataId, group, new AbstractListener() {
@Override
public void receiveConfigInfo(String s) {
groupKeyCache.get(GroupKey.getKey(dataId, group)).set(s);
}
@Override
public String toString() {
return String.format("sca nacos config annotation cache config listener");
}
});
}
return groupKeyCache.get(GroupKey.getKey(dataId, group)).get();
}
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
Class clazz = bean.getClass();
NacosConfig annotationBean = AnnotationUtils.findAnnotation(clazz, NacosConfig.class);
if (annotationBean != null) {
handleBeanNacosConfigAnnotation(annotationBean.dataId(), annotationBean.group(), annotationBean.key(), annotationBean.refreshed(), beanName, bean, annotationBean.defaultValue());
return bean;
}
for (Field field : getBeanFields(clazz)) {
handleFiledAnnotation(bean, beanName, field);
}
for (Method method : getBeanMethods(clazz)) {
handleMethodAnnotation(bean, beanName, method);
}
return bean;
}
private List getBeanFields(Class clazz) {
List res = new ArrayList<>();
ReflectionUtils.doWithFields(clazz, field -> res.add(field));
return res;
}
private List getBeanMethods(Class clazz) {
List res = new ArrayList<>();
ReflectionUtils.doWithMethods(clazz, method -> res.add(method));
return res;
}
private void handleFiledAnnotation(Object bean, String beanName, Field field) {
NacosConfig annotation = AnnotationUtils.getAnnotation(field, NacosConfig.class);
if (annotation != null) {
handleFiledNacosConfigAnnotation(annotation, beanName, bean, field);
}
}
private void handleBeanNacosConfigAnnotation(String dataId, String group, String key, boolean refreshed, String beanName, Object bean,
String defaultValue) {
try {
String config = getDestContent(getGroupKeyContent(dataId, group, refreshed), key);
if (!org.springframework.util.StringUtils.hasText(config)) {
config = defaultValue;
}
//Init bean properties.
if (org.springframework.util.StringUtils.hasText(config)) {
Object targetObject = convertContentToTargetType(config, bean.getClass());
//yaml and json to object
BeanUtils.copyProperties(targetObject, bean, getNullPropertyNames(targetObject));
}
String refreshTargetKey = beanName + "#instance#";
if (!refreshed) {
log.info("[Nacos Config] refresh is set to false,do not register listener for {} to bean {} ", refreshTargetKey, bean);
return;
}
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
if (currentTarget != null) {
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
currentTarget.getTarget(), bean);
targetListenerMap.get(refreshTargetKey).setTarget(bean);
return;
}
log.info("[Nacos Config] register {} listener on {} ", refreshTargetKey,
bean);
TargetRefreshable listener = null;
if (org.springframework.util.StringUtils.hasText(key)) {
listener = new NacosPropertiesKeyListener(bean, wrapArrayToSet(key)) {
@Override
public void configChanged(ConfigChangeEvent event) {
try {
ConfigChangeItem changeItem = event.getChangeItem(key);
String newConfig = changeItem == null ? null : changeItem.getNewValue();
if (!org.springframework.util.StringUtils.hasText(newConfig)) {
newConfig = defaultValue;
}
if (org.springframework.util.StringUtils.hasText(newConfig)) {
Object targetObject = convertContentToTargetType(newConfig, getTarget().getClass());
//yaml and json to object
BeanUtils.copyProperties(targetObject, getTarget(), getNullPropertyNames(targetObject));
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config instance key listener , key %s , target %s ] ", key, bean);
}
};
}
else {
listener = new NacosConfigRefreshableListener(bean) {
@Override
public void receiveConfigInfo(String configInfo) {
if (!org.springframework.util.StringUtils.hasText(configInfo)) {
configInfo = defaultValue;
}
if (org.springframework.util.StringUtils.hasText(configInfo)) {
Object targetObject = convertContentToTargetType(configInfo, bean.getClass());
//yaml and json to object
BeanUtils.copyProperties(targetObject, getTarget(), getNullPropertyNames(targetObject));
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config instance listener , key %s , target %s ] ", key, bean);
}
};
}
getNacosConfigManager().getConfigService()
.addListener(dataId, group, listener);
targetListenerMap.put(refreshTargetKey, listener);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private void handleMethodNacosConfigKeysChangeListener(NacosConfigKeysListener annotation, String beanName, Object bean,
Method method) {
String dataId = annotation.dataId();
String group = annotation.group();
try {
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1 || !ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0])) {
throw new RuntimeException(
"NacosConfigKeysChangeListener must be marked as a single parameter with ConfigChangeEvent");
}
String refreshTargetKey = beanName + "#method#" + methodSignature(method);
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
if (currentTarget != null) {
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
currentTarget.getTarget(), bean);
targetListenerMap.get(refreshTargetKey).setTarget(bean);
return;
}
log.info("[Nacos Config] register {} listener on {} ", refreshTargetKey,
bean);
// annotation on string.
NacosPropertiesKeyListener nacosPropertiesKeyListener = new NacosPropertiesKeyListener(bean, wrapArrayToSet(annotation.interestedKeys()),
wrapArrayToSet(annotation.interestedKeyPrefixes())) {
@Override
public void configChanged(ConfigChangeEvent event) {
ReflectionUtils.invokeMethod(method, this.getTarget(), event);
}
@Override
public String toString() {
return String.format("sca nacos config listener on bean method %s", bean + "#" + methodSignature(method));
}
};
nacosPropertiesKeyListener.setLastContent(getGroupKeyContent(dataId, group, true));
getNacosConfigManager().getConfigService().addListener(dataId, group,
nacosPropertiesKeyListener);
targetListenerMap.put(refreshTargetKey, nacosPropertiesKeyListener);
}
catch (Throwable e) {
throw new RuntimeException(e);
}
}
private Set wrapArrayToSet(String... arrayKeys) {
return new HashSet<>(Arrays.asList(arrayKeys));
}
private String methodSignature(Method method) {
StringBuilder signature = new StringBuilder(method.getName() + "(");
Class>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
signature.append(parameterTypes[i].getSimpleName());
if (i < parameterTypes.length - 1) {
signature.append(", ");
}
}
signature.append(")");
return signature.toString();
}
private void handleMethodNacosConfigListener(NacosConfigListener annotation, String beanName, Object bean, Method method) {
String dataId = annotation.dataId();
String group = annotation.group();
String key = annotation.key();
try {
Type[] parameterTypes = method.getGenericParameterTypes();
if (parameterTypes.length != 1) {
throw new RuntimeException(
"@NacosConfigListener must be over a method with a single parameter");
}
String configInfo = getGroupKeyContent(dataId, group, true);
String refreshTargetKey = beanName + "#method#" + methodSignature(method);
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
if (currentTarget != null) {
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
currentTarget.getTarget(), bean);
targetListenerMap.get(refreshTargetKey).setTarget(bean);
return;
}
log.info("[Nacos Config] register {} listener on {} ", refreshTargetKey,
bean);
TargetRefreshable listener = null;
if (org.springframework.util.StringUtils.hasText(key)) {
listener = new NacosPropertiesKeyListener(bean, wrapArrayToSet(key)) {
@Override
public void configChanged(ConfigChangeEvent event) {
try {
ConfigChangeItem changeItem = event.getChangeItem(key);
String newConfig = changeItem == null ? null : changeItem.getNewValue();
if (org.springframework.util.StringUtils.hasText(newConfig)) {
if (invokePrimitiveMethod(method, getTarget(), newConfig)) {
return;
}
Object targetObject = convertContentToTargetType(newConfig, parameterTypes[0]);
ReflectionUtils.invokeMethod(method, getTarget(), targetObject);
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config key listener , key %s , target %s ] ", key, bean + "#" + methodSignature(method));
}
};
((AbstractConfigChangeListener) listener).fillContext(dataId, group);
if (!annotation.initNotify()) {
((AbstractConfigChangeListener) listener).setLastContent(configInfo);
}
}
else {
listener = new NacosConfigRefreshableListener(bean) {
@Override
public void receiveConfigInfo(String configInfo) {
if (org.springframework.util.StringUtils.hasText(configInfo)) {
try {
if (invokePrimitiveMethod(method, getTarget(), configInfo)) {
return;
}
Object targetObject = convertContentToTargetType(configInfo, parameterTypes[0]);
ReflectionUtils.invokeMethod(method, getTarget(), targetObject);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config listener , target %s ] ", bean + "#" + methodSignature(method));
}
};
}
getNacosConfigManager().getConfigService().addListener(dataId, group, listener);
targetListenerMap.put(refreshTargetKey, listener);
if (annotation.initNotify() && org.springframework.util.StringUtils.hasText(configInfo)) {
try {
log.info("[Nacos Config] init notify listener of {} on {} start...", refreshTargetKey,
bean);
listener.receiveConfigInfo(configInfo);
log.info("[Nacos Config] init notify listener of {} on {} finished ", refreshTargetKey,
bean);
}
catch (Throwable throwable) {
log.warn("[Nacos Config] init notify listener error", throwable);
throw throwable;
}
}
}
catch (Throwable e) {
throw new RuntimeException(e);
}
}
Object convertContentToTargetType(String rawContent, Type type) {
if (String.class.getCanonicalName().equals(type.getTypeName())) {
return rawContent;
}
if (Properties.class.getCanonicalName().equals(type.getTypeName())) {
//properties and yaml config to properties.
Properties properties = new Properties();
try {
if (org.springframework.util.StringUtils.hasText(rawContent)) {
properties = PropertiesUtils.convertToProperties(rawContent);
}
}
catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
return properties;
}
return ObjectUtils.convertToObject(rawContent, type);
}
private void handleFiledNacosConfigAnnotation(NacosConfig annotation, String beanName, Object bean, Field field) {
String dataId = annotation.dataId();
String group = annotation.group();
String key = annotation.key();
try {
ReflectionUtils.makeAccessible(field);
handleFiledNacosConfigAnnotationInner(dataId, group, key, annotation.refreshed(), beanName, bean, field, annotation.defaultValue());
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private void handleFiledNacosConfigAnnotationInner(String dataId, String group, String key, boolean refreshed, String beanName, Object bean,
Field field, String defaultValue) {
try {
String config = getDestContent(getGroupKeyContent(dataId, group, refreshed), key);
if (!org.springframework.util.StringUtils.hasText(config)) {
config = defaultValue;
}
//primitive type
if (handPrimitiveFiled(field, dataId, group, config, key, defaultValue, refreshed, beanName, bean)) {
return;
}
//for other type.
if (org.springframework.util.StringUtils.hasText(config)) {
Object targetObject = convertContentToTargetType(config, field.getGenericType());
//yaml and json to object
ReflectionUtils.setField(field, bean, targetObject);
}
String refreshTargetKey = beanName + "#filed#" + field.getName();
if (!refreshed) {
log.info("[Nacos Config] refresh is set to false,do not register listener for {} to bean {} ", refreshTargetKey, bean);
return;
}
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
if (currentTarget != null) {
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
currentTarget.getTarget(), bean);
targetListenerMap.get(refreshTargetKey).setTarget(bean);
return;
}
log.info("[Nacos Config] register {} listener on {} ", refreshTargetKey,
bean);
TargetRefreshable listener = null;
if (org.springframework.util.StringUtils.hasText(key)) {
listener = new NacosPropertiesKeyListener(bean, wrapArrayToSet(key)) {
@Override
public void configChanged(ConfigChangeEvent event) {
try {
ConfigChangeItem changeItem = event.getChangeItem(key);
String newConfig = changeItem == null ? null : changeItem.getNewValue();
if (!org.springframework.util.StringUtils.hasText(newConfig)) {
newConfig = defaultValue;
}
if (org.springframework.util.StringUtils.hasText(newConfig)) {
Object targetObject = convertContentToTargetType(newConfig, field.getGenericType());
ReflectionUtils.setField(field, getTarget(), targetObject);
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config key listener , key %s , target %s ] ", key, bean + "#" + field.getName());
}
};
}
else {
listener = new NacosConfigRefreshableListener(bean) {
@Override
public void receiveConfigInfo(String configInfo) {
if (!org.springframework.util.StringUtils.hasText(configInfo)) {
configInfo = defaultValue;
}
if (org.springframework.util.StringUtils.hasText(configInfo)) {
Object targetObject = convertContentToTargetType(configInfo, field.getGenericType());
ReflectionUtils.setField(field, getTarget(), targetObject);
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config key listener , key %s , target %s ] ", key, bean + "#" + field.getName());
}
};
}
getNacosConfigManager().getConfigService()
.addListener(dataId, group, listener);
targetListenerMap.put(refreshTargetKey, listener);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private boolean handPrimitiveFiled(Field field, String dataId, String group, String config, String key, String defaultValue, boolean refreshed, String beanName, Object bean) throws Exception {
if (field.getType().isPrimitive()) {
if (org.springframework.util.StringUtils.hasText(config)) {
try {
setPrimitiveFiled(field, bean, config);
}
catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
String refreshTargetKey = beanName + "#filed#" + field.getName();
if (!refreshed) {
log.info("[Nacos Config] refresh is set to false,do not register listener for {} to bean {} ", refreshTargetKey, bean);
return true;
}
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
if (currentTarget != null) {
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
currentTarget.getTarget(), bean);
targetListenerMap.get(refreshTargetKey).setTarget(bean);
return true;
}
log.info("[Nacos Config] register {} listener on {} ", refreshTargetKey,
bean);
TargetRefreshable listener = null;
if (org.springframework.util.StringUtils.hasText(key)) {
listener = new NacosPropertiesKeyListener(bean, wrapArrayToSet(key)) {
@Override
public void configChanged(ConfigChangeEvent event) {
try {
ConfigChangeItem changeItem = event.getChangeItem(key);
String newConfig = changeItem == null ? null : changeItem.getNewValue();
if (!org.springframework.util.StringUtils.hasText(newConfig)) {
newConfig = defaultValue;
}
if (org.springframework.util.StringUtils.hasText(newConfig)) {
setPrimitiveFiled(field, getTarget(), newConfig);
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config key listener , key %s , target %s ] ", key, bean + "#" + field.getName());
}
};
}
else {
listener = new NacosConfigRefreshableListener(bean) {
@Override
public void receiveConfigInfo(String configInfo) {
if (!org.springframework.util.StringUtils.hasText(configInfo)) {
configInfo = defaultValue;
}
if (org.springframework.util.StringUtils.hasText(configInfo)) {
try {
setPrimitiveFiled(field, getTarget(), configInfo);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public String toString() {
return String.format("[spring cloud alibaba nacos config key listener , key %s , target %s ] ", key, bean + "#" + field.getName());
}
};
}
getNacosConfigManager().getConfigService()
.addListener(dataId, group, listener);
targetListenerMap.put(refreshTargetKey, listener);
return true;
}
return false;
}
private boolean setPrimitiveFiled(Field filed, Object bean, String value) throws Exception {
if (filed.getType() == int.class) {
filed.setInt(bean, Integer.parseInt(value));
}
else if (filed.getType() == Integer.class) {
ReflectionUtils.setField(filed, bean, Integer.valueOf(value));
}
else if (filed.getType() == long.class) {
filed.setLong(bean, Long.parseLong(value));
}
else if (filed.getType() == Long.class) {
ReflectionUtils.setField(filed, bean, Long.valueOf(value));
}
else if (filed.getType() == boolean.class) {
filed.setBoolean(bean, Boolean.parseBoolean(value));
}
else if (filed.getType() == Boolean.class) {
ReflectionUtils.setField(filed, bean, Boolean.valueOf(value));
}
else if (filed.getType() == double.class) {
filed.setDouble(bean, Double.parseDouble(value));
}
else if (filed.getType() == Double.class) {
ReflectionUtils.setField(filed, bean, Double.valueOf(value));
}
else if (filed.getType() == float.class) {
filed.setFloat(bean, Float.parseFloat(value));
}
else if (filed.getType() == Float.class) {
ReflectionUtils.setField(filed, bean, Float.valueOf(value));
}
else {
return false;
}
return true;
}
private boolean invokePrimitiveMethod(Method method, Object bean, String value) throws Exception {
Class> parameterType = method.getParameterTypes()[0];
if (parameterType == int.class) {
ReflectionUtils.invokeMethod(method, bean, Integer.parseInt(value));
}
else if (parameterType == Integer.class) {
ReflectionUtils.invokeMethod(method, bean, Integer.valueOf(value));
}
else if (parameterType == long.class) {
ReflectionUtils.invokeMethod(method, bean, Long.parseLong(value));
}
else if (parameterType == Long.class) {
ReflectionUtils.invokeMethod(method, bean, Long.valueOf(value));
}
else if (parameterType == boolean.class) {
ReflectionUtils.invokeMethod(method, bean, Boolean.parseBoolean(value));
}
else if (parameterType == Boolean.class) {
ReflectionUtils.invokeMethod(method, bean, Boolean.valueOf(value));
}
else if (parameterType == double.class) {
ReflectionUtils.invokeMethod(method, bean, Double.parseDouble(value));
}
else if (parameterType == Double.class) {
ReflectionUtils.invokeMethod(method, bean, Double.valueOf(value));
}
else if (parameterType == float.class) {
ReflectionUtils.invokeMethod(method, bean, Float.parseFloat(value));
}
else if (parameterType == Float.class) {
ReflectionUtils.invokeMethod(method, bean, Float.valueOf(value));
}
else {
return false;
}
return true;
}
private String getDestContent(String content, String key) throws Exception {
if (org.springframework.util.StringUtils.hasText(key)) {
Properties properties = PropertiesUtils.convertToProperties(content);
return properties.getProperty(key);
}
else {
return content;
}
}
private void handleMethodAnnotation(final Object bean, String beanName, final Method method) {
NacosConfigKeysListener keysAnnotation = AnnotationUtils.getAnnotation(method, NacosConfigKeysListener.class);
if (keysAnnotation != null) {
ReflectionUtils.makeAccessible(method);
handleMethodNacosConfigKeysChangeListener(keysAnnotation, beanName, bean, method);
return;
}
NacosConfigListener configAnnotation = AnnotationUtils.getAnnotation(method, NacosConfigListener.class);
if (configAnnotation != null) {
ReflectionUtils.makeAccessible(method);
handleMethodNacosConfigListener(configAnnotation, beanName, bean, method);
return;
}
if (!applicationContext.containsBeanDefinition(beanName)) {
return;
}
BeanDefinition beanDefinition = ((GenericApplicationContext) applicationContext).getBeanDefinition(beanName);
if (beanDefinition instanceof AnnotatedBeanDefinition) {
MethodMetadata factoryMethodMetadata = (((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata());
if (factoryMethodMetadata != null) {
MergedAnnotations annotations = factoryMethodMetadata.getAnnotations();
if (annotations != null && annotations.isPresent(NacosConfig.class)) {
MergedAnnotation nacosConfigMergedAnnotation = annotations.get(NacosConfig.class);
Map stringObjectMap = nacosConfigMergedAnnotation.asMap();
String dataId = (String) stringObjectMap.get("dataId");
String group = (String) stringObjectMap.get("group");
String key = (String) stringObjectMap.get("key");
String defaultValue = (String) stringObjectMap.get("defaultValue");
handleBeanNacosConfigAnnotation(dataId, group, key, true, beanName, bean, defaultValue);
}
}
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private NacosConfigManager getNacosConfigManager() {
if (this.nacosConfigManager == null) {
nacosConfigManager = this.applicationContext.getBean(NacosConfigManager.class);
}
return nacosConfigManager;
}
private static String[] getNullPropertyNames(Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set nullPropertyNames = new HashSet<>();
for (PropertyDescriptor pd : pds) {
String propertyName = pd.getName();
try {
Object propertyValue = src.getPropertyValue(propertyName);
if (propertyValue == null) {
nullPropertyNames.add(propertyName);
}
}
catch (NotReadablePropertyException e) {
//ignore
nullPropertyNames.add(propertyName);
}
}
return nullPropertyNames.toArray(new String[0]);
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosConfig.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Nacos Config annotation.
*
* @author shiyiyue1102
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface NacosConfig {
String group();
String dataId();
String key() default "";
String defaultValue() default "";
boolean refreshed() default true;
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosConfigKeysListener.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @ConfigChangeEvent
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface NacosConfigKeysListener {
String dataId();
String group();
String[] interestedKeys() default {};
String[] interestedKeyPrefixes() default {};
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosConfigListener.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface NacosConfigListener {
String dataId();
String group();
String key() default "";
boolean initNotify() default false;
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosConfigRefreshableListener.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import com.alibaba.nacos.api.config.listener.AbstractListener;
public abstract class NacosConfigRefreshableListener extends AbstractListener implements TargetRefreshable {
Object target;
NacosConfigRefreshableListener(Object target) {
this.target = target;
}
public Object getTarget() {
return target;
}
@Override
public void setTarget(Object target) {
this.target = target;
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosPropertiesKeyListener.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.util.Set;
import com.alibaba.nacos.api.config.ConfigChangeEvent;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.common.utils.CollectionUtils;
public abstract class NacosPropertiesKeyListener extends AbstractConfigChangeListener {
Set interestedKeys;
Set interestedKeyPrefixes;
NacosPropertiesKeyListener(Object target) {
super(target);
}
NacosPropertiesKeyListener(Object target, Set interestedKeys) {
this(target);
this.interestedKeys = interestedKeys;
}
public NacosPropertiesKeyListener(Object target, Set interestedKeys, Set interestedKeyPrefixes) {
this(target);
this.interestedKeys = interestedKeys;
this.interestedKeyPrefixes = interestedKeyPrefixes;
}
@Override
public final void receiveConfigChange(ConfigChangeEvent event) {
if (CollectionUtils.isNotEmpty(interestedKeys) || CollectionUtils.isNotEmpty(interestedKeyPrefixes)) {
boolean foundInterested = false;
for (ConfigChangeItem changeItem : event.getChangeItems()) {
if (interestedKeys != null && matchesInterestedKey(changeItem.getKey(), interestedKeys)) {
foundInterested = true;
break;
}
if (interestedKeyPrefixes != null) {
for (String prefix : interestedKeyPrefixes) {
if (changeItem.getKey().startsWith(prefix)) {
foundInterested = true;
break;
}
}
}
}
if (!foundInterested) {
return;
}
}
configChanged(event);
}
/**
* Check whether the changed key matches any of the interested keys.
*
* For YAML array/list configurations, the config change parser flattens keys
* with array indices (e.g. {@code myList[0]}, {@code myList[1]}), but users
* typically register interest in the base key ({@code myList}). This method
* handles both exact matches and array-indexed key matches by stripping the
* first {@code [index]} suffix and checking against the interested keys.
*
* @param changedKey the key from the {@link ConfigChangeItem}
* @param interestedKeys the set of keys the listener is interested in
* @return {@code true} if the changed key matches any interested key
*/
private boolean matchesInterestedKey(String changedKey, Set interestedKeys) {
if (interestedKeys.contains(changedKey)) {
return true;
}
// Handle array-indexed keys: "key[0]" or "key[0].nested" should match "key"
int bracketIndex = changedKey.indexOf('[');
if (bracketIndex > 0) {
String baseKey = changedKey.substring(0, bracketIndex);
return interestedKeys.contains(baseKey);
}
return false;
}
@Override
public String toString() {
return "NacosPropertiesKeyListener{" + "interestedKeys=" + interestedKeys + ", interestedKeyPrefixes="
+ interestedKeyPrefixes + '}' + "@" + hashCode();
}
public abstract void configChanged(ConfigChangeEvent event);
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/ObjectUtils.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.lang.reflect.Type;
import org.springframework.util.StringUtils;
final class ObjectUtils {
private ObjectUtils() {
}
public static Object convertToObject(String content, Type clazz) {
if (!StringUtils.hasText(content)) {
return null;
}
return convertFormJsonContent(content, clazz);
}
private static Object convertFormJsonContent(String content, Type clazz) {
return JsonUtils.toObj(content, clazz);
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/PropertiesUtils.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.io.StringReader;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.common.utils.StringUtils;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
final class PropertiesUtils {
private PropertiesUtils() {
}
public static Properties convertToProperties(String content) throws Exception {
if (StringUtils.isBlank(content)) {
return new Properties();
}
try {
return convertFormYamlContent(content);
}
catch (Exception e) {
return convertFormPropertiesContent(content);
}
}
private static Properties convertFormPropertiesContent(String content) throws Exception {
Properties properties = new Properties();
properties.load(new StringReader(content));
return properties;
}
private static Properties convertFormYamlContent(String content) {
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Map yamlMap = yaml.load(content);
Properties properties = new Properties();
flattenMap("", yamlMap, properties);
return properties;
}
private static void flattenMap(String prefix, Map map, Properties properties) {
for (Map.Entry entry : map.entrySet()) {
String key =
prefix.isEmpty() ? String.valueOf(entry.getKey()) : prefix + "." + String.valueOf(entry.getKey());
if (entry.getValue() instanceof Map) {
flattenMap(key, (Map) entry.getValue(), properties);
}
else {
properties.setProperty(key, entry.getValue().toString());
}
}
}
}
================================================
FILE: spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/ScaYamlConfigChangeParser.java
================================================
/*
* Copyright 2013-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.client.config.impl.YmlChangeParser;
import com.alibaba.nacos.common.utils.StringUtils;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.composer.ComposerException;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.error.MarkedYAMLException;
public class ScaYamlConfigChangeParser extends YmlChangeParser {
private static final String INVALID_CONSTRUCTOR_ERROR_INFO = "could not determine a constructor for the tag";
public ScaYamlConfigChangeParser() {
super();
}
@Override
public Map doParse(String oldContent, String newContent, String type) {
Map oldMap = Collections.emptyMap();
Map newMap = Collections.emptyMap();
try {
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
if (StringUtils.isNotBlank(oldContent)) {
oldMap = yaml.load(oldContent);
oldMap = getFlattenedMap(oldMap);
}
if (StringUtils.isNotBlank(newContent)) {
newMap = yaml.load(newContent);
newMap = getFlattenedMap(newMap);
}
}
catch (MarkedYAMLException e) {
handleYamlException(e);
}
return filterChangeData(oldMap, newMap);
}
private void handleYamlException(MarkedYAMLException e) {
if (e.getMessage().startsWith(INVALID_CONSTRUCTOR_ERROR_INFO) || e instanceof ComposerException) {
throw new NacosRuntimeException(NacosException.INVALID_PARAM,
"AbstractConfigChangeListener only support basic java data type for yaml. If you want to listen "
+ "key changes for custom classes, please use `Listener` to listener whole yaml configuration and parse it by yourself.",
e);
}
throw e;
}
private Map getFlattenedMap(Map source) {
Map result = new LinkedHashMap<>(128);
buildFlattenedMap(result, source, null);
return result;
}
private void buildFlattenedMap(Map result, Map source, String path) {
for (Iterator> itr = source.entrySet().iterator(); itr.hasNext(); ) {
Map.Entry e = itr.next();
String key = String.valueOf(e.getKey());
if (StringUtils.isNotBlank(path)) {
if (key.startsWith("[")) {
key = path + key;
}
else {
key = path + '.' + key;
}
}
if (e.getValue() instanceof String) {
result.put(key, e.getValue());
}
else if (e.getValue() instanceof Map) {
@SuppressWarnings("unchecked") Map map = (Map) e.getValue();
buildFlattenedMap(result, map, key);
}
else if (e.getValue() instanceof Collection) {
@SuppressWarnings("unchecked") Collection