SpringCloudAlibaba簡單Demo

前言

  • 什么是 Spring Cloud ?
    Spring Cloud 是構建在 Spring Boot 基礎之上,用于快速構建分布式系統的通用模式的工具集。或者說,換成大家更為熟知的,用于構建微服務的技術棧。

  • Spring Cloud 和 Spring Boot 的區別和關系?
    1.Spring Boot 專注于快速方便的開發單個個體微服務。
    2.Spring Cloud 是關注全局的微服務協調整理治理框架以及一整套的落地解決方案,它將 Spring Boot 開發的一個個單體微服務整合并管理起來,為各個微服務之間提供:配置管理,服務發現,斷路器,路由,微代理,事件總線等的集成服務。
    3.Spring Boot 可以離開 Spring Cloud 獨立使用,但是 Spring Cloud 離不開 Spring Boot ,屬于依賴的關系。

總結:
Spring Boot ,專注于快速,方便的開發單個微服務個體。
Spring Cloud ,關注全局的服務治理框架。

組件選擇

圖片來源于 Bilibili-尚硅谷 https://www.bilibili.com/video/BV18E411x7eT?p=4

版本選擇

開發項目最忌諱的就是版本對不上后期解決各種bug,項目搭建一定不能犯的錯誤

Spring Boot、Spring Cloud、Spring Coud Alibaba版本選擇官網: 版本說明

代碼開源地址

https://gitee.com/zhuheguo/cloud-demo2022

項目搭建

1.創建父項目

File -> new Project -> maven -> Next

File -> new Project -> maven

填寫項目名稱 -> Finish

父POM可以刪除不需要的文件(父項目只需要POM文件)

項目結構圖

pom文件配置

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <spring.cloud.alibaba-version>2021.1</spring.cloud.alibaba-version>
        <spring.cloud-version>2020.0.1</spring.cloud-version>
        <spring.boot.version>2.4.2</spring.boot.version>
        <lombok.version>1.18.16</lombok.version>
        <hutool.version>5.7.19</hutool.version>
        <fastjson.version>1.2.75</fastjson.version>
        <druid.version>1.1.22</druid.version>
        <mysql.version>8.0.23</mysql.version>
        <mybatis.plus.version>3.4.2</mybatis.plus.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!--Lombok項目是一個Java庫,它會自動插入編輯器和構建工具中,Lombok提供了一組有用的注釋,用來消除Java類中的大量樣板代碼-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

        <!--Hutool是一個小而全的Java工具類庫,通過靜態方法封裝,降低相關API的學習成本,提高工作效率,使Java擁有函數式語言般的優雅,讓Java語言也可以“甜甜的”。-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

        <!-- fastjson json轉換 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>

2.創建子模塊

同樣是創建maven項目,不過是在項目右鍵創建,后面操作和創建父POM項目是一樣的


分布式配置中心 --> Nacos Config

創建子模塊項目名cloud-config-service-8001

修改pom.xml添加依賴

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--2021以上版本需要引入該jar才能使bootstrap配置文件生效-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    </dependencies>

添加主啟動類com.cloud.pay.ConfigPayMain8001

package com.cloud.pay;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/25 9:00
 */
@SpringBootApplication
public class ConfigPayMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigPayMain8001.class,args);
    }
}

添加測試接口com.cloud.pay.rest.ConfigPayController

package com.cloud.pay.rest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/25 9:07
 */
@RestController
@RefreshScope
public class ConfigPayController {

    @Value("${key}")
    private String key;

    @GetMapping("/config")
    public ResponseEntity configPayTest() {
        return ResponseEntity.ok("test--config--key : " + key);
    }
}

resource添加bootstrap.yml

management:
  endpoints:
    web:
      exposure:
        include: '*'
spring:
  application:
    name: cloud-config-service
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml
        group: DEFAULT_GROUP
        namespace: cloud-demo
        #extension-configs:
        #  - dataId: seata.yaml
        #    refresh: true
  profiles:
    active: dev
server:
  port: 8001

安裝Naocs:https://www.cnblogs.com/konglxblog/p/15820333.html

添加命名空間cloud-demo

添加配置文件cloud-config-service-dev.yaml


key: abc123

啟動com.cloud.pay.ConfigPayMain8001并訪問http://localhost:8001/config

修改cloud-config-service-dev.yaml并刷新http://localhost:8001/config


注冊中心-服務注冊 --> Nacos discovery

新建子模塊cloud-discovery-client-8002

修改POM

<dependencies>
        <!--服務注冊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.netflix.ribbon</groupId>
                    <artifactId>ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

創建主啟動類com.cloud.pay.DiscoveryPayMain8002

package com.cloud.pay;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/24 18:09
 */
@SpringBootApplication
@EnableDiscoveryClient
public class DiscoveryPayMain8002 {
    public static void main(String[] args) {
        SpringApplication.run(DiscoveryPayMain8002.class,args);
    }
}

resource中添加application.yml

server:
  port: 8002
spring:
  application:
    name: cloud-discovery-client
  cloud:
    loadbalancer:
      cache:
        enabled: false
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: cloud-demo
        group: DEFAULT_GROUP
management:
  endpoints:
    web:
      exposure:
        include: '*'

添加測試接口com.cloud.pay.rest.DiscoveryPayController

package com.cloud.pay.rest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/24 18:23
 */
@RestController
public class DiscoveryPayController {

    @Value("${server.port}")
    private Integer port;

    @GetMapping("/discovery")
    public ResponseEntity<String> discovery() {
        return ResponseEntity.ok(port + "-->discovery");
    }
}

啟動com.cloud.pay.DiscoveryPayMain8002并訪問http://localhost:8002/discovery

查看服務列表可以看見cloud-discovery-client則服務注冊成功

服務消費和RPC遠程調用+負載均衡 --> Nacos Discovery + OpenFeign + Loadbalancer

創建子模塊cloud-feign-consumer-9001

修改pom.xml

<dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.netflix.ribbon</groupId>
                    <artifactId>ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

添加主啟動類com.cloud.pay.FeignPayMain9001

package com.cloud.pay;

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: zhuheguo
 * @Date: 2022/4/25 10:08
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignPayMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(FeignPayMain9001.class,args);
    }
}

resource中添加application.yml

server:
  port: 9001
spring:
  application:
    name: cloud-feign-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: cloud-demo
        group: DEFAULT_GROUP
management:
  endpoints:
    web:
      exposure:
        include: '*'

添加RPC調用接口com.cloud.pay.service.TestService

package com.cloud.pay.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/25 10:15
 */
@FeignClient("cloud-discovery-client")
@Component
public interface TestService {

    /**
     * 調用cloud-discovery-client的服務提供者
     *
     * @return
     */
    @GetMapping("/discovery")
    ResponseEntity<String> discovery();
}

添加測試接口com.cloud.pay.rest.FeignPayController

package com.cloud.pay.rest;

import com.cloud.pay.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/25 10:13
 */
@RestController
@Slf4j
public class FeignPayController {

    @Resource
    private TestService service;

    @Value("${server.port}")
    private Integer port;

    @GetMapping("/feign")
    public ResponseEntity<String> test() {
        final ResponseEntity<String> responseEntity = service.discovery();
        log.info("HTTP Status::{}", responseEntity.getStatusCodeValue());
        log.info("body::{}", responseEntity.getBody());
        return ResponseEntity.ok(port + "--->" + responseEntity.getBody());
    }
}

啟動com.cloud.pay.FeignPayMain9001和服務提供者cloud-discovery-client-8002的啟動類com.cloud.pay.DiscoveryPayMain8002并訪問http://localhost:9001/feign嘗試多刷新幾次

發現可以通過9001調用8002端口提供的服務,但是反復刷新只能一直調用8002,我們可以利用8002修改端口啟動8003 (不會可以參考 Idea中一個服務按多個端口同時啟動

啟動DiscoveryPayMain8003服務再反復刷新http://localhost:9001/feign發現會輪詢8002和8003(你也可以多啟動幾個測試)

服務網關 --> gateway

創建子模塊cloud-gateway-service-7001

修改pom.xml

<dependencies>
        <!--服務注冊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.netflix.ribbon</groupId>
                    <artifactId>ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <!--服務網關-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>

添加主啟動類com.cloud.pay.GatewayMain7001

package com.cloud.pay;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/25 14:01
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(GatewayMain7001.class, args);
    }
}

添加配置文件application.yml

management:
  endpoints:
    web:
      exposure:
        include: '*'
spring:
  application:
    name: cloud-gateway-service
  cloud:
    nacos:
      discovery:
        namespace: cloud-demo
        server-addr: localhost:8848
    gateway:
      routes:
        - id: pay
          uri: lb://cloud-discovery-client
          predicates:
            - Path=/discovery**
        - id: order
          uri: lb://cloud-feign-consumer
          predicates:
            - Path=/feign**
server:
  port: 7001

啟動com.cloud.pay.GatewayMain7001并訪問http://localhost:7001/feignhttp://localhost:7001/discovery測試


更多配置測試:https://www.cnblogs.com/babycomeon/p/11161073.html

服務降級 --> sentinel

新建子模塊cloud-sentinel-service-6001

修改pom.xml

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.netflix.ribbon</groupId>
                    <artifactId>ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

添加主啟動類com.cloud.pay.SentinelMain6001.java

package com.cloud.pay;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/25 17:27
 */
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelMain6001 {
    public static void main(String[] args) {
        SpringApplication.run(SentinelMain6001.class,args);
    }
}

添加application.yml

management:
  endpoints:
    web:
      exposure:
        include: '*'
spring:
  application:
    name: cloud-sentinel-service
  cloud:
    nacos:
      discovery:
        namespace: cloud-demo
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
server:
  port: 6001

添加測試接口com.cloud.pay.rest.SentinelController

package com.cloud.pay.rest;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/25 17:28
 */
@RestController
public class SentinelController {

    @GetMapping("/sentinel")
    public ResponseEntity sentinel() {
        return ResponseEntity.ok("sentinel");
    }
}

安裝sentinel:https://blog.csdn.net/Kevinnsm/article/details/117479096

啟動com.cloud.pay.SentinelMain6001.java和sentinel管控頁面并登錄,然后訪問http://localhost:6001/sentinel后查看http://localhost:8080/

新增流控規則后嘗試快速刷新和每秒刷新一次http://localhost:6001/sentinel


測試發現規則限定每秒只能訪問一次,規則范圍為的被Sentinel限流了

QPS:每秒查詢率(QPS,Queries-per-second)是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。

更多配置測試:http://www.lxweimin.com/p/35ba0d96450d

分布式事務

安裝:單獨文章介紹http://www.lxweimin.com/p/d08ee4567749
主要是安裝配置麻煩一點,使用就非常簡單

添加三個子模塊cloud-seata-order-service-5001 | cloud-seata-storage-service-5002 | cloud-seata-account-service-5003

修改pom.xml

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--服務注冊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.netflix.ribbon</groupId>
                    <artifactId>ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <!--RPC框架-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--分布式事務-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>
        <!--mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis.plus.version}</version>
        </dependency>
        <!-- 實現對數據庫連接池的自動化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- MySql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
            <scope>runtime</scope>
        </dependency>
        <!-- 連接池 阿里巴巴數據源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
    </dependencies>

主啟動類OrderMain5001 三個項目都一樣需要主啟動類,代碼是一樣的不重復貼了

package com.cloud.order;

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: zhuheguo
 * @Date: 2022/4/21 13:51
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderMain5001 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain5001.class, args);
    }
}

實體類com.cloud.order.domain.Order 也是每個項目都有,具體的看源碼吧,這里算是在復習SpringBoot了

package com.cloud.order.domain;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.math.BigDecimal;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 13:53
 */
@Data
@TableName("t_order")
public class Order {

    private Long id;

    /**
     * 用戶id
     */
    private Long userId;

    /**
     * 產品id
     */
    private Long productId;

    /**
     * 數量
     */
    private Integer count;

    /**
     * 金額
     */
    private BigDecimal money;

    /**
     * 訂單狀態:0:創建中;1:已完結
     */
    private Integer status;
}

數據庫持久化接口com.cloud.order.service.mapper.OrderMapper

package com.cloud.order.service.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cloud.order.domain.Order;
import org.apache.ibatis.annotations.Mapper;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 14:19
 */
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}

訂單業務邏輯接口com.cloud.order.service.OrderService

package com.cloud.order.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.cloud.order.domain.Order;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 14:21
 */
public interface OrderService extends IService<Order> {

    /**
     * 創建訂單
     * @param order
     */
    void create(Order order);
}

RPC遠程調用庫存微服務接口com.cloud.order.service.StorageService

package com.cloud.order.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 14:54
 */
@FeignClient(value = "cloud-seata-storage-service")
@Component
public interface StorageService {

    /**
     * 庫存扣減
     *
     * @param productId 產品id
     * @param count     數量
     * @return
     */
    @PostMapping(value = "/storage/decrease")
    ResponseEntity decrease(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
}

RPC遠程調用賬戶微服務接口com.cloud.order.service.AccountService

package com.cloud.order.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 14:54
 */
@FeignClient("cloud-seata-account-service")
@Component
public interface AccountService {
    /**
     * 余額扣減
     *
     * @param userId 用戶id
     * @param money  金額
     * @return
     */
    @PostMapping(value = "/account/decrease")
    ResponseEntity decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
}

訂單業務實現接口com.cloud.order.service.impl.OrderServiceImpl

package com.cloud.order.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloud.order.domain.Order;
import com.cloud.order.service.AccountService;
import com.cloud.order.service.OrderService;
import com.cloud.order.service.StorageService;
import com.cloud.order.service.mapper.OrderMapper;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 14:24
 */
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Resource
    private StorageService storageService;

    @Resource
    private AccountService accountService;

    @Override
    @GlobalTransactional(name = "cloud_create_order",rollbackFor = Exception.class)
    public void create(Order order) {
        log.info("開始新建訂單");
        this.save(order);
        log.info("訂單微服務開始調用庫存微服務,做庫存扣減");
        storageService.decrease(order.getProductId(), order.getCount());
        log.info("訂單微服務開始調用庫存微服務,做庫存扣減 end---");
        log.info("訂單微服務開始調用賬戶微服務,做余額扣減");
        accountService.decrease(order.getUserId(), order.getMoney());
        log.info("訂單微服務開始調用賬戶微服務,做余額扣減 end---");
        log.info("修改訂單狀態");
        order.setStatus(0);
        this.saveOrUpdate(order);
        log.info("修改訂單狀態 end---");
        log.info("訂單處理結束");
    }
}

訂單前端控制器com.cloud.order.rest.OrderController

package com.cloud.order.rest;

import com.cloud.order.domain.Order;
import com.cloud.order.service.OrderService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 功能描述:
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 13:54
 */
@RestController
public class OrderController {

    @Resource
    private OrderService orderService;

    @GetMapping("/order/create")
    public ResponseEntity create(Order order) {
        orderService.create(order);
        return new ResponseEntity("創建訂單成功", HttpStatus.OK);
    }
}

數據源配置類com.cloud.order.config.DataSourceProxyConfig

package com.cloud.order.config;

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

/**
 * 功能描述:使用seata對數據源進行代理
 *
 * @Author: zhuheguo
 * @Date: 2022/4/21 15:11
 */
@Configurable
public class DataSourceProxyConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }
    @Bean
    public DataSourceProxy dataSourceProxy(DataSource dataSource){
        return new DataSourceProxy(dataSource);
    }

    @Bean
    public SqlSessionFactory sessionFactoryBean(DataSourceProxy dataSourceProxy)throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSourceProxy);
        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
        return sqlSessionFactoryBean.getObject();
    }
}

配置文件application.yml

management:
  endpoints:
    web:
      exposure:
        include: '*'
server:
  port: 5001
spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: cloud-seata-order-service
  cloud:
    nacos:
      discovery:
        namespace: cloud-demo
        server-addr: localhost:8848
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/seata_order?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123456

#分布式事務配置
seata:
  application-id: ${spring.application.name}
  enabled: true
  enable-auto-data-source-proxy: true
  #分組名稱
  tx-service-group: my_test_tx_group
  #服務配置
  service:
    disable-global-transaction: false
    vgroup-mapping:
      my_test_tx_group: default
    grouplist:
      default: localhost:8091
  #配置中心配置
  config:
    type: nacos
    nacos:
      application: seata-server
      namespace: seata
      serverAddr: localhost:8848
      group: SEATA_GROUP
  #注冊中心配置
  registry:
    type: nacos
    nacos:
      application: seata-server
      namespace: seata
      server-addr: localhost:8848
      group: SEATA_GROUP

另外兩個模塊請看源碼,結構是一樣的,順帶演示了Spring boot 整合mybatis plus項目的搭建

實體類對應的sql初始化在父項目的sql文件夾中

完成后啟動測試,請先啟動服務提供者(賬戶和庫存微服務),后啟動訂單微服務,訪問http://localhost:5001/order/create?userId=1&productId=1&count=10&money=100

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容