Spring Cloud
1、框架版本选择
Spring Cloud : Hoxton.SR1
Spring Boot : 2.2.2.RELEASE
Spring Cloud Alibaba : 2.1.0.RELEASE
Java : 8
Maven : 3.5 及以上
MySql : 5.7 及以上
本次学习版本必须与使用以上版本,避免各版本之间兼容问题导致项目冲突。
2、查看Spring Cloud与Spring Boot之间的依赖关系
同时用boot和cloud,需要照顾cloud,由cloud决定boot版本
通过Spring官网查询:访问Spring官网(https://spring.io/projects/spring-cloud#learn),在对应版本的Spring Cloud后面点击Reference Doc,可以看到明显的"Supported Boot Version"字样,这里会显示当前Spring Cloud版本所支持的Spring Boot版本。
通过Spring初始化器网站查询:访问Spring初始化器网站(https://start.spring.io/actuator/info),这个网站会返回一串JSON数据,其中包含了Spring Cloud和Spring Boot的版本对应关系。通过这个JSON数据,可以清晰地看到每一个Spring Cloud版本下对应的Spring Boot版本。
我在学习的时候没有找到SR1的对应版本,可能因为版本过于老旧,能查到的最小的版本号为SR5,只能按照视频教学里对应的版本号建立项目了
https://spring.io/projects/spring-cloud#overview
更详细的依赖信息:
https://start.spring.io/actuator/info
3、关于Spring Cloud 各种组件的停更/升级/替换
以前:
现在:
4、微服务架构编码构建
4.1、编程风格
约定 > 配置 > 编码
4.2、IDEA新建project工作空间
4.2.1、微服务cloud整体聚合父工程Project
-
new project
-
总父工程
-
Maven
-
工程
-
字符编码
-
注解生效激活
-
Java编译版本选择
-
File Type过滤
添加:*.iead *.iml
会忽略添加了规则的文件、文件夹显式
4.2.2、父工程POM
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud2020</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 统一管理jar包版本 -->
<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>
<version>2.7.5</version>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.2.3、Maven工程落地
-
Maven中的DependencyManagement和Dependencies
Maven 使用dependencyManagement 元素来提供了一种管理依赖版本号的方式。
通常会在一个组织或者项目的最顶层的父POM 中看到dependencyManagement 元素。
使用pom.xml 中的dependencyManagement 元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。
Maven 会沿着子父层次向上走,找到一个拥有dependencyManagement 元素的项目,然后它就会使用这个
dependencyManagement 元素中指定的版本号,如果子项目中指定了版本号,那么会使用子项目中指定的版本。这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改 ;另外如果某个子项目需要另外的一个版本,只需要声明version就可。
dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。 如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;
-
maven中跳过单元测试
<build><!-- maven中跳过单元测试 --> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> </plugins> </build>
-
父工程创建完成执行mvn:install将父工程发布到仓库方便子工程继承
4.2.4、MySQL驱动说明
com.mysql.jdbc.Driver和mysql-connector-java 5一起用。
com.mysql.cj.jdbc.Driver和mysql-connector-java 6 一起用。
com.mysql.cj.jdbc.Driver是mysql-connector-java 6 中的特性,相比mysql-connector-java 5 多了一个时区:serverTimezone,把数据源配置的驱动改一下就好了。
org.gjt.mm.mysql.Driver是当时最好的MySQL JDBC,但不是MySQL公司的,然后MySQL将MM的JDBC驱动 收为官方的JDBC驱动,所以将驱动的package也改了,但还保留了org.gjt.mm.mysql.Driver这个路径的引用,也就是你使用新版的JDBC驱动时还可以通过这个来引用,打开下载的新版JDBC驱动的jar文件可以看到,只有一个文件的目录是org.gjt.mm.mysql,就是为了兼容而设计的。
4.3、Rest微服务工程构件
分别建立:
微服务消费者订单模块 cloud-provider-payment8001
微服务消费者订单模块 cloud-consumer-order80
4.3.1、微服务消费者订单模块 cloud-provider-payment8001
4.3.1.1、建module
父工程POM文件会增加子工程
4.3.1.2、改POM
pom.xml(cloud-provider-payment8001)
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud2020</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-provider-payment8001</artifactId>
<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>
<version>1.1.10</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<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>
</project>
4.3.1.3、写YML
cloud-provider-payment8001-application.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驱动包 com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.92.88:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
druid:
validation-query: select 1
test-while-idle: true
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities # 所有Entity别名类所在包
4.3.1.4、主启动
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
4.3.1.5、业务类
-
建库建表
CREATE TABLE `payment` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `serial` varchar(200) DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
-
entities
Payment.javapackage com.atguigu.springcloud.entities; import lombok.AllArgsConstructor; import lombok.Data; import javax.validation.constraints.Null; import java.io.Serializable; @Data @AllArgsConstructor @Null public class Payment implements Serializable { private Long id; private String serial; }
CommResult.java
package com.atguigu.springcloud.entities; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class CommResult<T> { private Integer code; private String message; private T data; public CommResult(Integer code, String message) { this(code, message, null); } }
-
dao
PaymentDao.java
package com.atguigu.springcloud.dao; import com.atguigu.springcloud.entities.Payment; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @Mapper public interface PaymentDao { public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
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="com.atguigu.springcloud.dao.PaymentDao"> <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id"> insert into payment(serial) values(#{serial}) </insert> <resultMap id="BaseResultMap" type="com.atguigu.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>
-
service
PaymentService.java
package com.atguigu.springcloud.service; import com.atguigu.springcloud.entities.Payment; import org.apache.ibatis.annotations.Param; public interface PaymentService { public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
PaymentServiceImpl.java
package com.atguigu.springcloud.service.impl; import com.atguigu.springcloud.dao.PaymentDao; import com.atguigu.springcloud.entities.Payment; import com.atguigu.springcloud.service.PaymentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class PaymentServiceImpl implements PaymentService { @Autowired private PaymentDao paymentDao; public int create(Payment payment) { return paymentDao.create(payment); } public Payment getPaymentById(Long id) { return paymentDao.getPaymentById(id); } }
-
controller
PaymentController.javapackage com.atguigu.springcloud.controller; import com.atguigu.springcloud.entities.CommResult; import com.atguigu.springcloud.entities.Payment; import com.atguigu.springcloud.service.PaymentService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j public class PaymentController { @Autowired private PaymentService paymentService; @PostMapping(value = "/payment/create") public CommResult create(@RequestBody Payment payment) { // 不要忘记加上RequestBody注解 // 否则 4.3.2.6测试增加记录时,值会传递不过来 int result = paymentService.create(payment); log.info("*************插入结果:" + result); if (result > 0) { return new CommResult(200, "插入数据库成功", result); } else { return new CommResult(444, "插入数据库失败", null); } } @GetMapping(value = "/payment/get/{id}") public CommResult getPaymentById(@PathVariable("id") Long id) { Payment payment = paymentService.getPaymentById(id); log.info("*************查询结果:" + payment); if (payment != null) { return new CommResult(200, "查询成功", payment); } else { return new CommResult(444, "没有对应记录,查询失败,ID:" + id, null); } } }
4.3.1.6、测试
查询:
插入:post请求使用PostMan模拟
由于微服务后续会启动多个模块的服务,所以需要使用 Run Dashboard 工具来启动和管理各个服务。
通过修改idea的workspace.xml的方式来快速打开Run Dashboard窗口
文件路径:E:\WorkSpace\iead-workspace\cloud2020.idea (当前工程所在的文件目录)<option name="configurationTypes"> <set> <option value="SpringBootApplicationConfigurationType" /> </set> </option>
2019之后的版本可以通过找到对应的选项来启动此功能
详细参考:https://www.jb51.net/program/317804oei.htm
4.3.2、微服务消费者订单模块 cloud-consumer-order80
4.3.2.1、建module
4.3.2.2、改POM
pom.xml(cloud-consumer-order80)
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud2020</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-consumer-order80</artifactId>
<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>
<version>1.1.10</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<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>
</project>
4.3.2.3、写YML
cloud-consumer-order80-application.yml
server:
port: 80
4.3.2.4、主启动
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
4.3.2.5、业务类
-
entities
Payment.javapackage com.atguigu.springcloud.entities; import lombok.AllArgsConstructor; import lombok.Data; import javax.validation.constraints.Null; import java.io.Serializable; @Data @AllArgsConstructor @Null public class Payment implements Serializable { private Long id; private String serial; }
CommResult.java
package com.atguigu.springcloud.entities; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class CommResult<T> { private Integer code; private String message; private T data; public CommResult(Integer code, String message) { this(code, message, null); } }
-
RestTemplate
RestTemplate提供了多种便捷访问远程Http服务的方法,
是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集
官网地址:使用:
使用restTemplate访问restful接口非常的简单粗暴无脑。
(url, requestMap, ResponseBean.class)这三个参数分别代表
REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。 -
config配置类
ApplicationContextConfig.javapackage com.atguigu.springcloud.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ApplicationContextConfig { @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } }
-
controller
OrderController.java
package com.atguigu.springcloud.controller;
import com.atguigu.springcloud.entities.CommResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class OrderController {
public static final String PAYMENT_URL = "http://localhost:8001";
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommResult<Payment> create(Payment payment) {
return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommResult<Payment> getPayment(@PathVariable("id") Long id) {
return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommResult.class);
}
}
4.3.2.6、测试
4.3.3、热部署
-
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>
-
父工程POM增加插件
<build> <finalName>cloud-provider-payment8001</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>
-
设置IDEA
Ctrl + Shift + s
Ctrl + Shift + Alt + /
新版本可能找不到compiler.automake.allow.when.app.running,这是因为这个选项放到了设置中,Ctrl + Shift + s 然后找到对应设置进行勾选。
-
重启
如果设置后未生效可能因为版本过久,需要重启。
4.3.4、工程重构
-
观察问题:系统中有重复的结构
-
新建一个模块 cloud-api-commons 用来封装通用类以及工具类
-
改POM
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud2020</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>cloud-api-commons</artifactId> <dependencies> <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>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.1.0</version> </dependency> </dependencies> </project>
-
封装entities
-
Maven项目,将模块放入本地仓库
-
对已有模块进行改造
删除
微服务消费者订单模块 cloud-provider-payment8001
微服务消费者订单模块 cloud-consumer-order80
中 entities的通用类在各自木块的POM文件中引入自定义的api通用包
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency>
注意!!!
在启动时 cloud-provider-payment8001 模块时报错,这是因为在 PaymentMapper.xml 文件中,需要对 Payment 的引用路径进 行修改:
其中 id 为 create 的 parameterType 的类型需要由 “Payment” 修改为 “entities.Payment”;
其中 id 为 BaseResult 的 resultMap ,type引用的类型由 “com.atguigu.springcloud.entities.Payment” 修改为 “entities.Payment”
详细参考:http://t.csdnimg.cn/eXwAC测试结果:
目前的框架结构: