SpringCloud学习笔记
- 成熟分布式微服务架构包含技术模块
- SpringCloud与SpringBoot版本选择
- SpringCloud各技术模块的技术选择
- SpringCloud实现订单-支付微服务
- 创建父工程(管理子工程即各个微服务)
- 父工程的build.gradle配置
- 父工程的settings.gradle配置
- 创建支付子工程(payment_native)
- 支付微服务具体业务类及目录结构
- 目录结构
- 具体业务类
- 创建订单子工程(order_native)
- build.gradle配置文件
- 订单微服务具体业务类及目录结构
- 目录结构
- 具体业务类
- 拆分目的
成熟分布式微服务架构包含技术模块
服务的注册与发现、服务调用、服务熔断、负载均衡、服务降级、服务消息队列、配置中心管理、服务网关、服务监控、全链路追踪、自动化构建部署、服务定时任务调度操作等等…
SpringCloud与SpringBoot版本选择
通过查看SpringCloud官网的推荐搭配即可。
更细致的搭配可以通过访问网址,查看返回的JSON串来获取。
JSON串解析网站
SpringCloud各技术模块的技术选择
服务注册中心:Eureka(可被Nacos代替)
服务调用:Ribbon(推荐LoadBalancer)
服务调用2:Feign(可被OpenFeign代替)
服务降级:Hystrix(可被sentienl代替)
服务网关:gateway
服务配置:Config(可被Nacos代替)
服务总线:Bus(可被Nacos代替)
SpringCloud实现订单-支付微服务
创建父工程(管理子工程即各个微服务)
正常新建Gradle项目
这里命名为CloudParent
由于父工程的主要作用是管理底下的各个子工程(微服务)所以不需要实现具体的业务,可以将它的src包删除,如下:
父工程的build.gradle配置
一般在父工程的build.gradle中引入一些子工程通用的依赖和配置,这样在每个子工程中就无需重复引入了,如下:
// 父工程配置
plugins {
// 可以使用api编译
id 'java-library'
id 'org.springframework.boot' version '2.5.6'
id 'io.spring.dependency-management' version '1.1.0'
}
ext {
springCloudVersion = '2020.0.6'
springBootVersion = '2.5.6'
slf4jVersion = '1.7.25'
logbackVersion = '1.2.3'
}
repositories {
mavenCentral()
}
// 全局配置
allprojects {
group 'org.gks.springcloud'
version '1.0-SNAPSHOT'
// 指定jdk版本
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
//业务编码字符集,注意这是指定源码解码的字符集[编译器
compileJava.options.encoding "UTF-8"
//测试编码字符集,注意这是指定源码解码的字符集[编译器]
compileTestJava.options.encoding "UTF-8"
//编译JAVA文件时采用UTF-8 :注意这是指定源码编码的字符集【源文件】
tasks.withType (JavaCompile) {
options.encoding = "UTF-8"
}
//编译JAVA文件时采用UTF-8 :注意这是指定文档编码的字符集【源文件】
tasks.withType (Javadoc) {
options.encoding = "UTF-8"
}
}
// 子项目的通用配置
subprojects {
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
// 可以使用api编译
apply plugin: 'java-library'
jar.enabled = true
repositories {
mavenCentral()
}
// 子项目通用依赖
dependencies {
implementation "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
implementation "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
implementation "ch.qos.logback:logback-classic:${logbackVersion}"
implementation 'org.projectlombok:lombok'
}
}
父工程的settings.gradle配置
目前只有一个父工程,所以其中只有如下配置(当前工程作为root):
后续随着子工程的不断加入,settings.gradle中会不断include新工程。见后续章节
创建支付子工程(payment_native)
右击父工程选择new–》Module:
在弹出的对话框中继续选择创建Gradle项目
下一步,输入子工程名称,注意此时父工程已经指定了
点击finish,一个子工程就初步创建完毕了:
此时观察子工程的目录发现只有一个build.gradle,此时需要修改该配置文件,将多余部分删除只需要引入当前子工程所需的依赖和配置即可,因为通用的已经在父工程的配置文件中指定:
- 初始配置
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
- 修改后配置
plugins {
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'mysql:mysql-connector-java:8.0.26'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'com.baomidou:mybatis-plus-boot-starter:3.3.2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.aspectj:aspectjweaver:1.8.7'
}
修改完成后reload一下Gradle即可
build完成后通过侧边栏观察当前子工程所引入的依赖,发现不仅包含自己引入的也包含了父工程引入的:
但是此时该子项目的目录中依旧只有一个build.gradle配置文件,此时可以手动创建一个SpringBoot项目的常用目录:
在弹出的对话框中选择所需的模板目录结构:
这样创建完成后,就回到了我们熟悉的目录结构:
然后按需创建实现业务的包和类即可,别忘了SpringBoot的启动类和application.properties配置文件!!!
此时回到父工程中观察settings.gradle配置文件发现该子工程已经被自动引入了:
支付微服务具体业务类及目录结构
目录结构
具体业务类
实体类
//订单表实体类,包括主键(id)和订单序列号(serial)
public class Payment {
private Long id;
private String serial;
无参和全参构造函数
setter和getter
}
//统一响应实体类,包括响应码、响应信息和响应数据
public class CommandResult<T> {
private Integer code;
private String message;
private T data;
无参、两参和全参构造函数
setter和getter
}
controller层
@RestController
@RequestMapping("payment")
public class PaymentController {
@Autowired
private PaymentService paymentService;
@PostMapping("newData")
public CommandResult create(@RequestBody Payment payment){
Integer result = paymentService.create(payment);
if (result != 0){
return new CommandResult(200,"插入数据成功",result);
}
return new CommandResult(200,"插入数据失败",null);
}
@GetMapping("serialNum")
public CommandResult getPaymentById(Long id){
Payment result = paymentService.getPaymentById(id);
return new CommandResult(200,"查询数据成功",result);
}
}
service层
//接口
public interface PaymentService {
Integer create(Payment payment);
Payment getPaymentById(@Param("id") Long id);
}
//实现类
@Service
public class PaymentServiceImpl implements PaymentService {
@Autowired
private PaymentDAO paymentDAO;
@Override
public Integer create(Payment payment) {
return paymentDAO.create(payment);
}
@Override
public Payment getPaymentById(Long id) {
return paymentDAO.getPaymentById(id);
}
}
DAO层及映射XML
public interface PaymentDAO {
Integer create(@Param("payment")Payment payment);
Payment getPaymentById(@Param("id") Long id);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gks.pay.repository.PaymentDAO">
<sql id="allValumns" >
id,
serial
</sql>
<insert id="create" parameterType="Payment" >
INSERT INTO
payment(serial)
VALUES(#{payment.serial})
</insert>
<select id="getPaymentById" parameterType="Long" resultType="Payment">
SELECT
<include refid="allValumns"></include>
FROM
payment
WHERE
id=#{id}
</select>
</mapper>
创建订单子工程(order_native)
创建流程与创建支付子工程基本一致,因为订单子工程是向前端提供访问接口的微服务,不需要实现具体功能所以无需访问数据库,也就不用引入数据库相关的依赖。
build.gradle配置文件
plugins {
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.aspectj:aspectjweaver:1.8.7'
}
订单微服务具体业务类及目录结构
目录结构
具体业务类
RestTempleteConfig
因为要使用restTemplate所以需要进行配置并注入Bean
这里使用的是默认配置
@Configuration
public class RestTempleteConfig {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
实体类
与支付微服务中的一致
controller层
@RestController
@RequestMapping("order")
public class OrderController {
public static final String PAYMENT_URL = "http://localhost:8085/payment";
@Autowired
private RestTemplate restTemplate;
@GetMapping("newData")
public CommandResult create(Payment payment){
return restTemplate.postForObject(PAYMENT_URL+"/newData", payment,CommandResult.class);
}
@GetMapping("serialNum")
public CommandResult getPaymentById(Long id){
return restTemplate.getForObject(PAYMENT_URL+"/serialNum?id={id}", CommandResult.class, id);
}
}
restTemplate的使用方式和坑见以下文章:
关于RestTemplate postForObject方法请求 服务端Controller接受不到值的问题解决
关于getForObject()的正确用法
一文吃透接口调用神器RestTemplate
自此两个微服务搭建完成
拆分目的
支付微服务实现具体的业务(比如这里的新增订单、查询订单)
而订单微服务只是提供与前端交互的接口,其内部本质是对支付微服务的请求