前言
-
什么是 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
父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/feign和http://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
网友评论