SpringCloud简介
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式环境中运行良好,包括开发人员自己的笔记本电脑,裸机数据中心,以及Cloud Foundry等托管平台。
官网:https://spring.io/projects/spring-cloud
特点
Spring Cloud专注于为典型的用例和可扩展性机制(包括其他用例)提供良好的开箱即用体验。
-
分布式/版本化配置
-
服务注册和发现
-
路由
-
服务到服务的呼叫
-
负载均衡
-
断路器
-
全局锁
-
领导选举和集群状态
-
分布式消息传递
Spring Cloud 架构图
SpringCloud项目搭建
学习SpringCloud先要有,SpringBoot的相关知识,参考【SpringBoot】SpringBoot快速入门(一)
SpringBoot 是基于 SpringFramework 来构建的,SpringFramework 是一种 J2EE 的框架,SpringBoot 是一种快速构建 Spring 应用,SpringCloud 是构建 Spring Boot 分布式环境,也就是常说的云应用,SpringBoot 中流砥柱,承上启下
本例项目架构
环境准备
**** 1)JDK 环境必须是 1.8 及以上,本例使用版本:1.8.0_181
2)Maven 项目管理工具,3.6.0及以上版本,本例使用版本:3.6.3
3)开发工具使用 IDEA
搭建项目父工程
1、新建一个maven空工程test-springcloud
2、编写pom文件,引入项目所需要依赖的包
本例使用的SpringBoot版本是2.2.5.RELEASE,SpringCloud版本是Hoxton.SR3
使用其他版本,需要注意SpringBoot和SpringCloud版本的兼容问题
1 <!-- spring boot -->
2 <dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-dependencies</artifactId>
5 <version>2.2.5.RELEASE</version>
6 <type>pom</type>
7 <scope>import</scope>
8 </dependency>
9 <!-- spring cloud -->
10 <dependency>
11 <groupId>org.springframework.cloud</groupId>
12 <artifactId>spring-cloud-dependencies</artifactId>
13 <version>Hoxton.SR3</version>
14 <type>pom</type>
15 <scope>import</scope>
16 </dependency>
完整pom文件如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>com.test</groupId>
8 <artifactId>test-springcloud</artifactId>
9 <version>1.0-SNAPSHOT</version>
10 <packaging>pom</packaging>
11
12
13 <modules>
14 <module>test-springcloud-eureka-server8761</module>
15 <module>test-springcloud-order8000</module>
16 <module>test-springcloud-provider-payment8001</module>
17 </modules>
18
19
20 <!-- 统一管理jar包版本 -->
21 <properties>
22 <spring-boot.version>2.2.5.RELEASE</spring-boot.version>
23 <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
24 <!-- <spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>-->
25 <mybatis-spring-boot.version>2.1.2</mybatis-spring-boot.version>
26 <mysql.version>8.0.12</mysql.version>
27 <druid.version>1.1.21</druid.version>
28 <lombok.version>1.18.12</lombok.version>
29 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
30 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
31 <java.version>1.8</java.version>
32 </properties>
33
34
35 <!-- 依赖管理:子模块继承后,提供作用:锁定版本 + 子module 不用写 version -->
36 <dependencyManagement>
37 <dependencies>
38 <!-- spring boot -->
39 <dependency>
40 <groupId>org.springframework.boot</groupId>
41 <artifactId>spring-boot-dependencies</artifactId>
42 <version>${spring-boot.version}</version>
43 <type>pom</type>
44 <scope>import</scope>
45 </dependency>
46 <!-- spring cloud -->
47 <dependency>
48 <groupId>org.springframework.cloud</groupId>
49 <artifactId>spring-cloud-dependencies</artifactId>
50 <version>${spring-cloud.version}</version>
51 <type>pom</type>
52 <scope>import</scope>
53 </dependency>
54 <!-- spring cloud alibaba -->
55 <!-- <dependency>-->
56 <!-- <groupId>com.alibaba.cloud</groupId>-->
57 <!-- <artifactId>spring-cloud-alibaba-dependencies</artifactId>-->
58 <!-- <version>${spring-cloud-alibaba.version}</version>-->
59 <!-- <type>pom</type>-->
60 <!-- <scope>import</scope>-->
61 <!-- </dependency>-->
62
63 <!-- mybatis -->
64 <dependency>
65 <groupId>org.mybatis.spring.boot</groupId>
66 <artifactId>mybatis-spring-boot-starter</artifactId>
67 <version>${mybatis-spring-boot.version}</version>
68 </dependency>
69
70 <!-- mysql -->
71 <dependency>
72 <groupId>mysql</groupId>
73 <artifactId>mysql-connector-java</artifactId>
74 <version>${mysql.version}</version>
75 </dependency>
76
77 <!-- druid -->
78 <dependency>
79 <groupId>com.alibaba</groupId>
80 <artifactId>druid-spring-boot-starter</artifactId>
81 <version>${druid.version}</version>
82 </dependency>
83
84 <!-- lombok -->
85 <dependency>
86 <groupId>org.projectlombok</groupId>
87 <artifactId>lombok</artifactId>
88 <version>${lombok.version}</version>
89 </dependency>
90
91 <!-- test -->
92 <dependency>
93 <groupId>org.springframework.boot</groupId>
94 <artifactId>spring-boot-starter-test</artifactId>
95 <version>${spring-boot.version}</version>
96 <scope>test</scope>
97 <exclusions>
98 <exclusion>
99 <groupId>org.junit.vintage</groupId>
100 <artifactId>junit-vintage-engine</artifactId>
101 </exclusion>
102 </exclusions>
103 </dependency>
104 </dependencies>
105 </dependencyManagement>
106
107 <!-- SpringBoot打包插件,可以将代码打包成一个可执行的jar包 -->
108 <build>
109 <finalName>${project.artifactId}</finalName>
110 <plugins>
111 <plugin>
112 <groupId>org.apache.maven.plugins</groupId>
113 <artifactId>maven-compiler-plugin</artifactId>
114 <configuration>
115 <source>${java.version}</source>
116 <target>${java.version}</target>
117 </configuration>
118 </plugin>
119 <plugin>
120 <groupId>org.springframework.boot</groupId>
121 <artifactId>spring-boot-maven-plugin</artifactId>
122 <version>${spring-boot.version}</version>
123 <configuration>
124 <fork>true</fork>
125 <addResources>true</addResources>
126 </configuration>
127 </plugin>
128 </plugins>
129 </build>
130 </project>
131
132 pom.xml
pom.xml
3、项目结构图如下:
搭建Eureka注册中心
即Eureka的服务端
1、在父项目上,new module 新建一个模块Eureka注册中心,及Eureka服务端 test-springboot-eureka-server8761
2、编写pom.xml文件
Eureka服务端依赖如下:
1 <!-- eureka server -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
5 </dependency>
完整pom.xml文件如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <parent>
6 <artifactId>test-springcloud</artifactId>
7 <groupId>com.test</groupId>
8 <version>1.0-SNAPSHOT</version>
9 </parent>
10 <modelVersion>4.0.0</modelVersion>
11
12 <artifactId>test-springcloud-eureka-server8761</artifactId>
13
14 <dependencies>
15 <!-- eureka server -->
16 <dependency>
17 <groupId>org.springframework.cloud</groupId>
18 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
19 </dependency>
20
21 <!-- spring boot -->
22 <dependency>
23 <groupId>org.springframework.boot</groupId>
24 <artifactId>spring-boot-starter-web</artifactId>
25 </dependency>
26 <dependency>
27 <groupId>org.springframework.boot</groupId>
28 <artifactId>spring-boot-starter-actuator</artifactId>
29 </dependency>
30 <dependency>
31 <groupId>org.springframework.boot</groupId>
32 <artifactId>spring-boot-devtools</artifactId>
33 <scope>runtime</scope>
34 <optional>true</optional>
35 </dependency>
36
37 <dependency>
38 <groupId>org.springframework.boot</groupId>
39 <artifactId>spring-boot-starter-test</artifactId>
40 <scope>test</scope>
41 </dependency>
42
43 </dependencies>
44
45 <build>
46 <finalName>test-springcloud-eureka-server8761</finalName>
47 </build>
48 </project>
pom.xml
3、编写application.yml配置文件
1 # 端口
2 server:
3 port: 8761
4
5 spring:
6 application:
7 name: cloud-eureka-server
8
9 # Eureka配置
10 eureka:
11 instance:
12 # eureka服务端的实例名称
13 hostname: localhost
14 client:
15 # false表示不向注册中心注册自己
16 register-with-eureka: false
17 # false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检查服务
18 fetch-registry: false
19 # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
20 service-url:
21 defaultZone: http://localhost:8761/eureka
4、编辑SpringBoot启动类EurekaMain8761.java,并使用@EnableEurekaServer
1 // Eureka服务端
2 @EnableEurekaServer
3 @SpringBootApplication
4 public class EurekaMain8761 {
5 public static void main(String[] args) {
6 SpringApplication.run(EurekaMain8761.class, args);
7 }
8 }
5、启动test-springboot-eureka-server8761项目,使用地址:http://localhost:8761/,进行访问
搭建支付模块、服务提供者
即Eureka客户端
需要准备一个test_springcloud的mysql数据库,新建一张表payment,内容如下:
1 SET NAMES utf8mb4;
2 SET FOREIGN_KEY_CHECKS = 0;
3
4 -- ----------------------------
5 -- Table structure for payment
6 -- ----------------------------
7 DROP TABLE IF EXISTS `payment`;
8 CREATE TABLE `payment` (
9 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
10 `serial` varchar(255) DEFAULT '' COMMENT '流水号',
11 PRIMARY KEY (`id`)
12 ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
13
14 -- ----------------------------
15 -- Records of payment
16 -- ----------------------------
17 BEGIN;
18 INSERT INTO `payment` VALUES (1, 'No.1');
19 INSERT INTO `payment` VALUES (2, 'No.2');
20 INSERT INTO `payment` VALUES (3, 'No.3');
21 COMMIT;
22
23 SET FOREIGN_KEY_CHECKS = 1;
View Code
1、在父项目上,new module 新建一个模块支付模块,即Eureka客户端 test-springcloud-provider-payment8001
2、编写payment模块的pom.xml文件,引入Eureka 客户端依赖
1 <!-- eureka client -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
5 </dependency>
完整pom.xml文件如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <parent>
6 <artifactId>test-springcloud</artifactId>
7 <groupId>com.test</groupId>
8 <version>1.0-SNAPSHOT</version>
9 </parent>
10 <modelVersion>4.0.0</modelVersion>
11
12 <artifactId>test-springcloud-provider-payment8001</artifactId>
13
14 <dependencies>
15
16 <!-- eureka client -->
17 <dependency>
18 <groupId>org.springframework.cloud</groupId>
19 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
20 </dependency>
21
22 <!-- spring boot -->
23 <dependency>
24 <groupId>org.springframework.boot</groupId>
25 <artifactId>spring-boot-starter-web</artifactId>
26 </dependency>
27 <dependency>
28 <groupId>org.springframework.boot</groupId>
29 <artifactId>spring-boot-starter-actuator</artifactId>
30 </dependency>
31 <dependency>
32 <groupId>org.springframework.boot</groupId>
33 <artifactId>spring-boot-starter-jdbc</artifactId>
34 </dependency>
35 <dependency>
36 <groupId>org.springframework.boot</groupId>
37 <artifactId>spring-boot-devtools</artifactId>
38 <scope>runtime</scope>
39 <optional>true</optional>
40 </dependency>
41 <dependency>
42 <groupId>org.mybatis.spring.boot</groupId>
43 <artifactId>mybatis-spring-boot-starter</artifactId>
44 </dependency>
45 <dependency>
46 <groupId>org.projectlombok</groupId>
47 <artifactId>lombok</artifactId>
48 <optional>true</optional>
49 </dependency>
50 <!-- mysql -->
51 <dependency>
52 <groupId>mysql</groupId>
53 <artifactId>mysql-connector-java</artifactId>
54 </dependency>
55 <!-- druid -->
56 <dependency>
57 <groupId>com.alibaba</groupId>
58 <artifactId>druid-spring-boot-starter</artifactId>
59 </dependency>
60 <dependency>
61 <groupId>org.springframework.boot</groupId>
62 <artifactId>spring-boot-starter-test</artifactId>
63 <scope>test</scope>
64 </dependency>
65
66 </dependencies>
67
68 <build>
69 <finalName>test-springcloud-provider-payment8001</finalName>
70 </build>
71 </project>
View Code
3、编辑application.yml配置文件
1 # 端口
2 server:
3 port: 8001
4
5 spring:
6 application:
7 name: cloud-payment-service
8 # 数据源基本配置
9 datasource:
10 driver-class-name: com.mysql.cj.jdbc.Driver
11 url: jdbc:mysql://localhost:3306/test_springcloud?allowPublicKeyRetrieval=true&useSSL=true
12 username: admin
13 password: 123456
14
15 eureka:
16 client:
17 # 表示将自己注册进Eureka Server默认为true
18 register-with-eureka: true
19 # 是否从Eureka Server抓去已有的注册信息,默认是true
20 fetch-registry: true
21 # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
22 service-url:
23 defaultZone: http://localhost:8761/eureka
24
25 mybatis:
26 mapperLocations: classpath:mapper/*Mapper.xml
27 # 所有entity别名类所在的包
28 type-aliases-pachage: com.test.springcloud.entities
4、编写启动类
1 // Eureka客户端
2 @EnableEurekaClient
3 @SpringBootApplication
4 public class PaymentMain8001 {
5 public static void main(String[] args) {
6 SpringApplication.run(PaymentMain8001.class, args);
7 }
8 }
5、新建一个实体类Payment.java
1 @Data
2 @AllArgsConstructor
3 @NoArgsConstructor
4 public class Payment {
5 private Long id;
6 private String serial;
7 }
View Code
6、新建一个实体类映射文件 src/main/resources/mapper/PaymentMapper.xml
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3
4 <mapper namespace="com.test.springcloud.dao.PaymentDao">
5
6 <resultMap id="BaseResultMap" type="com.test.springcloud.entities.Payment" >
7 <id property="id" jdbcType="BIGINT" column="id" />
8 <result property="serial" jdbcType="VARCHAR" column="serial" />
9 </resultMap>
10
11 <insert id="insert" parameterType="com.test.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
12 INSERT INTO payment(serial) values(#{serial})
13 </insert>
14
15 <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap" >
16 SELECT * FROM payment WHERE id = #{id}
17 </select>
18 </mapper>
View Code
7、新建一个dao接口
1 @Mapper
2 public interface PaymentDao {
3 // 插入
4 public int insert(Payment payment);
5 // 获取
6 public Payment getPaymentById(@Param("id") Long id);
7 }
View Code
8、新建一个service接口
1 public interface PaymentService {
2 // 插入
3 public int insert(Payment payment);
4 // 获取
5 public Payment getPaymentById(Long id);
6 }
View Code
9、编写一个接口实现类
1 @Service
2 public class PaymentServiceImpl implements PaymentService {
3
4 @Autowired
5 private PaymentDao paymentDao;
6
7 public int insert(Payment payment) {
8 return paymentDao.insert(payment);
9 }
10
11 public Payment getPaymentById(Long id) {
12 return paymentDao.getPaymentById(id);
13 }
14 }
View Code
10、编辑一个通用结果类CommonResult.java
1 /**
2 * 通用结果
3 * @param <T>
4 */
5 @Data
6 @AllArgsConstructor
7 @NoArgsConstructor
8 public class CommonResult<T> {
9
10 private int code;
11 private String msg;
12 private T data;
13
14 public CommonResult(int code, String msg) {
15 this.code = code;
16 this.msg = msg;
17 }
18 }
View Code
11、新增一个Controller
1 @Slf4j
2 @RestController
3 public class PaymentController {
4
5
6 @Autowired
7 private PaymentService paymentService;
8
9 @Value("${server.port}")
10 private String serverPort;
11
12 @PostMapping("/payment/insert")
13 public CommonResult insert(@RequestBody Payment payment) {
14 int result = paymentService.insert(payment);
15 log.info("====== 插入结果:" + result);
16 if(result > 0) {
17 return new CommonResult(200, "插入数据成功,服务端口:" + serverPort);
18 }else {
19 return new CommonResult(500, "插入数据失败");
20 }
21
22 }
23
24 @GetMapping("/payment/get/{id}")
25 public CommonResult getPaymentById(@PathVariable("id") Long id) {
26 Payment result = paymentService.getPaymentById(id);
27
28 log.info("====== 查询结果:" + result);
29 if(result != null) {
30 return new CommonResult(200, "查询成功,服务端口:" + serverPort, result);
31 }else {
32 return new CommonResult(500, "查询失败");
33 }
34
35 }
36 }
View Code
12、启动payment模块,查看Eureka注册中心
访问地址:http://localhost:8001/payment/get/1
搭建订单模块、服务消费
1、在父项目上,new module 新建一个模块订单模块,即Eureka客户端 test-springcloud-order8000
2、编写order模块的pom.xml文件,引入Eureka 客户端依赖
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <parent>
6 <artifactId>test-springcloud</artifactId>
7 <groupId>com.test</groupId>
8 <version>1.0-SNAPSHOT</version>
9 </parent>
10 <modelVersion>4.0.0</modelVersion>
11
12 <artifactId>test-springcloud-order8000</artifactId>
13
14
15 <dependencies>
16
17 <!-- eureka client -->
18 <dependency>
19 <groupId>org.springframework.cloud</groupId>
20 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
21 </dependency>
22
23 <!-- spring boot -->
24 <dependency>
25 <groupId>org.springframework.boot</groupId>
26 <artifactId>spring-boot-starter-web</artifactId>
27 </dependency>
28 <dependency>
29 <groupId>org.springframework.boot</groupId>
30 <artifactId>spring-boot-starter-actuator</artifactId>
31 </dependency>
32 <dependency>
33 <groupId>org.springframework.boot</groupId>
34 <artifactId>spring-boot-devtools</artifactId>
35 <scope>runtime</scope>
36 <optional>true</optional>
37 </dependency>
38
39 <dependency>
40 <groupId>org.projectlombok</groupId>
41 <artifactId>lombok</artifactId>
42 <optional>true</optional>
43 </dependency>
44 <dependency>
45 <groupId>org.springframework.boot</groupId>
46 <artifactId>spring-boot-starter-test</artifactId>
47 <scope>test</scope>
48 </dependency>
49
50 </dependencies>
51
52 <build>
53 <finalName>test-springcloud-order8000</finalName>
54 </build>
55
56 </project>
View Code
3、编写application.yml配置文件
1 # 端口
2 server:
3 port: 8000
4
5 spring:
6 application:
7 name: cloud-order
8
9 eureka:
10 client:
11 # 表示将自己注册进Eureka Server默认为true
12 register-with-eureka: true
13 # 是否从Eureka Server抓去已有的注册信息,默认是true
14 fetch-registry: true
15 # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
16 service-url:
17 defaultZone: http://localhost:8761/eureka
4、编写启动类
1 @EnableEurekaClient
2 @SpringBootApplication
3 public class OrderMain80 {
4 public static void main(String[] args) {
5 SpringApplication.run(OrderMain80.class, args);
6 }
7 }
5、编写一个服务调用配置类,注入RestTemplate,调用服务
1 @Configuration
2 public class AppConfig {
3
4 /**
5 * 注入restTemplate,请用请求rest接口
6 * @return
7 */
8 @Bean
9 // 标注此注解后,RestTemplate就具有了客户端负载均衡能力
10 // 负载均衡技术依赖于的是Ribbon组件~
11 // RestTemplate都塞入一个loadBalancerInterceptor 让其具备有负载均衡的能力
12 @LoadBalanced
13 public RestTemplate restTemplate(){
14 return new RestTemplate();
15 }
16 }
6、编写实体类Payment.java
1 @Data
2 @AllArgsConstructor
3 @NoArgsConstructor
4 public class Payment {
5 private Long id;
6 private String serial;
7 }
View Code
7、编写通用返回类
1 @Data
2 @AllArgsConstructor
3 @NoArgsConstructor
4 public class CommonResult<T> {
5
6 private int code;
7 private String msg;
8 private T data;
9
10 public CommonResult(int code, String msg) {
11 this.code = code;
12 this.msg = msg;
13 }
14 }
View Code
8、编写Controller,使用RestTemplate调用服务
1 @RestController
2 @Slf4j
3 public class OrderController {
4
5 // public static final String PAYMENT_URL = "http://localhost:8001";
6 public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
7
8
9 @Autowired
10 private RestTemplate restTemplate;
11
12 @PostMapping("/consumer/payment/insert")
13 public CommonResult<Payment> insert(Payment payment){
14 log.info("====== 请求插入:" + payment);
15 return restTemplate.postForObject(PAYMENT_URL + "/payment/insert", payment, CommonResult.class);
16 }
17
18 @GetMapping("/consumer/payment/get/{id}")
19 public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
20 return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
21 }
22 }
9、启动order模块,查看Eureka注册中心