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)是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。

更多配置测试:https://www.jianshu.com/p/35ba0d96450d

分布式事务

安装:单独文章介绍https://www.jianshu.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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容