springcloud-基础入门(一)
微服务架构概述
- 微服务架构是一种架构模式, 它提倡将单一应用划分为一组小的服务, 服务之间相互协调, 相互配合.
- 每个服务运行在其独立的进程中, 服务与服务之间采用轻量级的通信机制互相协作(通常是基于HTTP协议的REST)
- 每个服务都围绕着具体业务进行构建, 并且能够被独立的部署到生产环境, 类生产环境等.
- 此外, 应当避免统一的, 集中式的服务管理机制, 对一个具体的服务而言, 应根据上下文, 选择合适的语言, 工具进行构建
- 基于分布式的微服务架构
- 服务注册与发现
- 服务调用
- 服务熔断
- 负载均衡
- 服务降级
- 服务消息队列
- 配置中心管理
- 服务网关
- 服务监控
- 全链路追踪
- 自动化构建部署
- 服务定时任务调度操作
SpringCloud简介
- 是什么
- SpringCloud = 分布式微服务架构的一站式解决方案, 是多种微服务架构落地技术的集合体, 俗称微服务全家桶.
- SpringCloud技术栈
- 服务注册发现 - Eureka
- 服务负载与调用 - Ribbon/Feign
- 服务熔断降级 - Hystrix
- 服务网关 - Zuul
- 服务配分布式配置 - SpringCloud Config
- 服务开发 - SpringBoot
版本的选择
- SpringBoot和SpringCloud版本选择
- 具体的选择
关于Cloud各种组件的停更/升级/替换
- 停更
- 停止更新, 但仍然可以使用.
- 被动修复bugs
- 不再接收和并请求
- 不再发布新版本
- Cloud的升级
订单-支付模块微服务
总父工程
- 搭建总的聚合父工程
- 创建一个maven工程: cloud2020
- 创建时勾选
- 注意
- 若创建完后报错
<reporting> <plugins> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> </plugin> </plugins> </reporting>
- 是因为缺少依赖, 加上即可
<dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </dependency>
- 若创建完后报错
- 父工程pom文件
- 添加packaging: 总的父工程
<packaging>pom</packaging>
- 管理各种依赖和插件
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.16.18</lombok.version> <mysql.version>5.1.47</mysql.version> <druid.version>1.1.16</druid.version> <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version> </properties> <!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version --> <dependencyManagement> <dependencies> <!--spring boot 2.2.2--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring cloud Hoxton.SR1--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring cloud alibaba 2.1.0.RELEASE--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.spring.boot.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <optional>true</optional> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build>
- dependencyManagement来提供一种管理依赖版本号的方式
- 该标签一般只在父工程中出现.
- 之后在子项目中就不用写version了, 版本和它保持一致.
- 它只确定规范, 并不引入具体的jar包.
- dependencyManagement来提供一种管理依赖版本号的方式
- maven中跳过单元测试, 节约时间
- 父工程创建完后执行mvn:install将父工程发布到仓库方便子工程继承.
Rest微服务工程构建(支付模块)
- 工程结构
- 如何构建微服务模块
- 建子module: cloud-provider-payment8001
- 改POM
<dependencies> <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> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
- 写yml
server: port: 8001 spring: application: name: cloud-payment-service datasource: type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root password: root mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: springcloud.entities # 所有entity实体类所在包 - 主启动
@SpringBootApplication public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class, args); } }
- 业务类: (controller - service - dao - mysql) -> Json串
- 建表SQL
CREATE TABLE payment( id BIGINT(20) PRIMARY KEY AUTO_INCREMENT, `serial` VARCHAR(200) DEFAULT '' );
- 创建entities
- Payment
@Data @NoArgsConstructor @AllArgsConstructor public class Payment implements Serializable { private Long id; private String serial; }
- json封装体CommonResult (前后端分离模式下, 后端只往前端传json串)
//返回通用的json实体串 @Data @NoArgsConstructor @AllArgsConstructor public class CommonResult<T> { private Integer code; private String message; private T data; public CommonResult(Integer code, String message) { this(code, message, null); } }
- Payment
- dao
- 接口PaymentDao
@Mapper public interface PaymentDao { public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
- mybatis的映射文件PaymentMapper.xml
<?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="springcloud.dao.PaymentDao"> <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id"> insert into payment(serial) values(#{serial}); </insert> <resultMap id="BaseResultMap" type="springcloud.entities.Payment"> <id column="id" property="id" jdbcType="BIGINT" /> <id column="serial" property="serial" jdbcType="VARCHAR"/> </resultMap> <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap"> select * from payment where id = #{id} </select> </mapper>
- 接口PaymentDao
- service
- 接口PaymentService
public interface PaymentService { public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
- 实现类
@Service public class PaymentServiceImpl implements PaymentService { @Resource private PaymentDao paymentDao; @Override public int create(Payment payment) { return paymentDao.create(payment); } @Override public Payment getPaymentById(Long id) { return paymentDao.getPaymentById(id); } }
- 接口PaymentService
- controller
@RestController @Slf4j public class PaymentController { @Resource private PaymentService paymentService; @PostMapping(value = "/payment/create") public CommonResult create(@RequestBody Payment payment) { int result = paymentService.create(payment); log.info("插入结果: " + result); if (result > 0) { return new CommonResult(200, "插入数据库成功", result); } return new CommonResult(444, "插入数据库失败"); } @GetMapping(value = "/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id) { Payment payment = paymentService.getPaymentById(id); log.info("插入结果: " + payment); if (payment != null) { return new CommonResult(200, "查询成功", payment); } return new CommonResult(444, "没有对应记录, 查询ID:" + id); } }
- 建表SQL
- 测试 - 使用Postman工具
- 测试插入: POST请求 - http://localhost:8001/payment/create?serial=T-46
- 测试查询: GET请求 - http://localhost:8001/payment/get/1
热部署Devtools
- 即代码改了以后, 可以自动重启服务器, 而不用手动重启.
- 添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>
- 添加插件
<!-- 在父工程中添加 --> <build> <finalName>cloud2020</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build>
- 开启自动编译的权限
- 更新值
- 在pom文件中 ctrl+alt+shift+/ -> Registry.. , 勾选如下两个选项
- 在pom文件中 ctrl+alt+shift+/ -> Registry.. , 勾选如下两个选项
- 重启IDEA
- 注意: 只在开发阶段使用项目热部署, 发布时必须关闭.
微服务消费者订单Module模块
- RestTemplate
- RestTemplate提供了多种便捷访问远程Http服务器的方法, 是一种简单便捷的访问restful服务模板类, 是Spring提供的用于访问Rest服务的客户端模板工具集.
- 使用时很简单
(url, requestMap, ResponseBean.class) 三个参数分别代表REST请求地址, 请求参数, HTTP响应转换被转成的对象类型.
- 建module
- 改pom
<dependencies> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
- 写yml
server: port: 80 # 浏览网页服务默认端口80
- 主启动
- 业务类
- entities: 同上
- config
@Configuration public class ApplicationContextConfig { @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } }
- OrderController
@RestController @Slf4j public class OrderController { private static final String PAYMENT_URL = "http://localhost:8001"; @Resource private RestTemplate restTemplate; //浏览器只能发get请求, 但下面调用的实质是post请求 @GetMapping("/consumer/payment/create") public CommonResult<Payment> create(Payment payment) { log.info(payment.toString()); String url = PAYMENT_URL + "/payment/create"; return restTemplate.postForObject(url, payment, CommonResult.class); } @GetMapping("/consumer/payment/get/{id}") public CommonResult<Payment> getPayment(@PathVariable("id")Long id) { String url = PAYMENT_URL + "/payment/get/" + id; return restTemplate.getForObject(url, CommonResult.class); } }
- 测试
- 查询: GET请求 - http://localhost/consumer/payment/get/1
- 插入: Get请求 - http://localhost/consumer/payment/create?serial=T-51 (不要忘记在支付模块中加入@RequestBody注解)