最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba 專欄
2、服務治理 Nacos Discovery
3、遠程調用負載均衡 Ribbon
4、遠程調用Feign
5、服務熔斷降級 Sentinel
源碼
1 一些說明
為了方便講解SpringCloud課程,我們以最常見的電商項目2個核心模塊:商品模塊、訂單模塊為例子,一一講解SpringCloud組件的使用。
學習SpringCloud組件要訣:
1>能解決啥問題
2>怎么解決(理解原理)
3>API調用(代碼怎么寫)–建議寫3遍–【1遍抄全,2遍思考,3遍掌握】
4>總結,開口表述
5>類比以前代碼結構
微服務-----完整項目按功能分類拆分成n個子項目/子模塊,這些子模塊能對外提供對應的功能。我們稱這些服務為微服務
落地到代碼:單看子項目,每個子項目就是一個完整項目(springmvc項目)----記住沒啥高大上的
商品微服務
- 對外提供查詢商品列表接口
- 對外提供查詢某個商品信息接口
訂單微服務
- 對外提供創(chuàng)建訂單接口
服務調用
在微服務架構中,最常見的場景就是微服務之間的相互調用。以下單為例子:客戶向訂單微服務發(fā)起一個下單的請求,在進行保存訂單之前需要調用商品微服務查詢商品的信息。
一般把調用方稱為服務消費者,把被調用方稱為服務提供者。
上例中,訂單微服務就是服務消費者, 而商品微服務是服務提供者。
2 技術選型
JDK17
持久層: MyBatis-Plus
數(shù)據(jù)庫: MySQL5.7
其他: SpringCloud Alibaba 技術棧
服務注冊與發(fā)現(xiàn):Nacos
分布式事務:Seata
網(wǎng)關:Spring Cloud Gateway
服務調用:OpenFeign
鑒權:Spring Authorization Server 、Oauth2.1
消息隊列:rocketmq
限流、熔斷:sentinel
鏈路追蹤:Micrometer Tracing
接口文檔:knife4j
3 模塊設計
— shop-parent 父工程
? — shop-product-api 商品微服務api 【存放商品實體】
? — shop-product-server 商品微服務 【端口:808x】
? — shop-order-api 訂單微服務api 【存放訂單實體】
? — shop-order-server 訂單微服務 【端口:809x】
shop-product-server:子項目-商品微服務,對外提供查詢商品信息的接口
shop-order-server:子項目-訂單微服務,對外提供創(chuàng)建訂單的接口
shop-product-api / shop-order-api : 各自微服務依賴的實體類,為啥要拆開?答案是:解耦
4 版本說明
? https://github.com/alibaba/spring-cloud-alibaba/wiki/版本說明
5 創(chuàng)建父工程
創(chuàng)建 shop-parent 一個maven工程,然后在pom.xml文件中添加下面內容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>shop</artifactId>
<version>1.0.0</version>
<name>shop-parent</name>
<packaging>pom</packaging>
<modules>
<module>shop-product-api</module>
<module>shop-product-server</module>
</modules>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>2022.0.0</spring-cloud.version>
<spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.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>
</dependencies>
</dependencyManagement>
</project>
6 創(chuàng)建商品微服務
6.1 創(chuàng)建shop-product-api項目,然后在pom.xml文件中添加下面內容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>shop</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>shop-product-api</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
6.2 創(chuàng)建實體類
package com.example.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
//商品
@Getter
@Setter
@ToString
@TableName("t_product")
public class Product implements Serializable {
//主鍵
@TableId(type= IdType.AUTO)
private Long id;
//商品名稱
private String name;
//商品價格
private Double price;
//庫存
private Integer stock;
}
6.3 創(chuàng)建shop-product-server項目,然后在pom.xml文件中添加下面內容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>shop</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>shop-product-server</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>shop-product-api</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
6.4 編寫配置文件application.yml
server:
port: 8081
spring:
application:
name: product-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop-product?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: aaaaaa
6.5 在數(shù)據(jù)庫中創(chuàng)建shop-product的數(shù)據(jù)庫
CREATE TABLE `t_product` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`name` varchar(255) DEFAULT NULL COMMENT '商品名稱',
`price` double(10,2) DEFAULT NULL COMMENT '商品價格',
`stock` int DEFAULT NULL COMMENT '庫存',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
INSERT INTO t_product VALUE(NULL,'小米','1000','5000');
INSERT INTO t_product VALUE(NULL,'華為','2000','5000');
INSERT INTO t_product VALUE(NULL,'蘋果','3000','5000');
INSERT INTO t_product VALUE(NULL,'OPPO','4000','5000');
6.6 創(chuàng)建ProductMapper
package com.example.server.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.domain.Product;
public interface ProductMapper extends BaseMapper<Product> {
}
6.7 創(chuàng)建ProductService接口和實現(xiàn)類
package com.example.server.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.domain.Product;
public interface ProductService extends IService<Product> {
}
package com.example.server.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.domain.Product;
import com.example.server.mapper.ProductMapper;
import com.example.server.service.ProductService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}
6.8 創(chuàng)建Controller
package com.example.server.controller;
import com.alibaba.fastjson2.JSON;
import com.example.domain.Product;
import com.example.server.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class ProductController {
@Autowired
private ProductService productService;
//商品信息查詢
@RequestMapping("/products/{pid}")
public Product findByPid(@PathVariable("pid") Long pid) {
log.info("接下來要進行{}號商品信息的查詢", pid);
Product product = productService.getById(pid);
log.info("商品信息查詢成功,內容為{}", JSON.toJSONString(product));
return product;
}
}
6.9 編寫啟動類ProductServer.java
package com.example.server;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.server.mapper")
public class ShopProductServerApplication {
public static void main(String[] args) {
SpringApplication.run(ShopProductServerApplication.class, args);
}
}
6.10 通過瀏覽器訪問服務
7 創(chuàng)建訂單微服務
7.1 創(chuàng)建shop-order-api項目,然后在pom.xml文件中添加下面內容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>shop</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>shop-order-api</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
7.2 創(chuàng)建實體類
package com.example.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
//訂單
@Getter
@Setter
@ToString
@TableName("t_order")
public class Order implements Serializable {
//訂單id
@TableId(type = IdType.AUTO)
private Long id;
//用戶id
private Long uid;
//用戶名
private String username;
//商品id
private Long pid;
//商品名稱
private String productName;
//商品單價
private Double productPrice;
//購買數(shù)量
private Integer number;
}
7.3 創(chuàng)建shop-order-server項目,然后在pom.xml文件中添加下面內容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>shop</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>shop-order-server</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>shop-order-api</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7.4 編寫配置文件application.yml
server:
port: 8091
spring:
application:
name: order-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop-order?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: aaaaaa
7.5 在數(shù)據(jù)庫中創(chuàng)建shop-order的數(shù)據(jù)庫
CREATE TABLE `t_order` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`uid` bigint DEFAULT NULL COMMENT '用戶id',
`username` varchar(255) DEFAULT NULL COMMENT '用戶名稱',
`pid` bigint DEFAULT NULL COMMENT '商品id',
`product_name` varchar(255) DEFAULT NULL COMMENT '商品名稱',
`product_price` double(255,0) DEFAULT NULL COMMENT '商品單價',
`number` int DEFAULT NULL COMMENT '購買數(shù)量',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
7.6 創(chuàng)建OrderMapper
package com.example.server.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.domain.Order;
public interface OrderMapper extends BaseMapper<Order> {
}
7.7 創(chuàng)建OrderService接口和實現(xiàn)類
package com.example.server.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.domain.Order;
public interface OrderService extends IService<Order> {
Order createOrder(Long pid, Long uid);
}
package com.example.server.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.domain.Order;
import com.example.server.mapper.OrderMapper;
import com.example.server.service.OrderService;
import org.springframework.stereotype.Service;
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Override
public Order createOrder(Long pid, Long uid) {
return null;
}
}
7.8 創(chuàng)建Controller
package com.example.server.controller;
import com.example.domain.Order;
import com.example.server.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/save")
public Order order(Long pid, Long uid){
return orderService.createOrder(pid, uid);
}
}
7.9 編寫啟動類OrderServer.java
package com.example.server;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.server.mapper")
public class ShopOrderServerApplication {
public static void main(String[] args) {
SpringApplication.run(ShopOrderServerApplication.class, args);
}
}
8 服務間如何進行遠程調用
現(xiàn)在存在一個問題,order-server服務創(chuàng)建訂單操作需要配置商品信息,此時怎么辦?
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
@Override
public Order createOrder(Long pid, Long uid) {
Order order = new Order();
//商品??
Product product = null;
order.setPid(pid);
order.setProductName(product.getName());
order.setProductPrice(product.getPrice());
//用戶
order.setUid(1L);
order.setUsername("dafei");
order.setNumber(1);
super.save(order);
return order;
}
}
思考,誰能提供商品信息查詢邏輯呢?
答案:product-server,.
問題來了,怎么調用?這里引入一個新問題:服務與服務間如何調用(交互)?
問題來了,怎么用java代碼調用發(fā)起http接口調用嗯?
答案是:RestTemplate
RestTempate 是SpringMVC提供專門用于訪問http請求的工具類
8.1 在shop-order-server項目啟動類上添加RestTemplate的bean配置
package com.example.server;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@MapperScan("com.example.server.mapper")
public class ShopOrderServerApplication {
public static void main(String[] args) {
SpringApplication.run(ShopOrderServerApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
8.2 在OrderServiceImpl中注入RestTemplate并實現(xiàn)遠程調用
package com.example.server.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.domain.Order;
import com.example.domain.Product;
import com.example.server.mapper.OrderMapper;
import com.example.server.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Autowired
private RestTemplate restTemplate;
@Override
public Order createOrder(Long pid, Long uid) {
Order order = new Order();
//商品
//方案1:通過restTemplate方式
String url = "http://localhost:8081/products/" + pid;
Product product = restTemplate.getForObject(url, Product.class);
order.setPid(pid);
order.setProductName(product.getName());
order.setProductPrice(product.getPrice());
//用戶
order.setUid(uid);
order.setUsername("張三");
order.setNumber(1);
System.out.println(order);
super.save(order);
return order;
}
}
上面操作確實完成的服務間調用問題,但是代碼很不優(yōu)雅,存在著一定小瑕疵,比如:ip,端口變了呢?
-
一旦服務提供者(商品服務)地址變化,就需要手工修改代碼
-
一旦是多個服務(商品服務)提供者,無法實現(xiàn)負載均衡功能
-
一旦服務變得越來越多,人工維護調用關系困難
那怎么辦呢, 這時候得引入SpringCloud Alibaba第一個組件:
**組件:**注冊中心–Nacos文章來源:http://www.zghlxwxcb.cn/news/detail-753937.html
功能:動態(tài)的實現(xiàn)服務治理。文章來源地址http://www.zghlxwxcb.cn/news/detail-753937.html
到了這里,關于最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服務環(huán)境搭建的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!