前言
什么是 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 ,關注全局的服務治理框架。
組件選擇
版本選擇
開發項目最忌諱的就是版本對不上后期解決各種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)是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。
更多配置測試: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