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 2 <dependency> 3 <groupId>org.springframework.bootgroupId> 4 <artifactId>spring-boot-dependenciesartifactId> 5 <version>2.2.5.RELEASEversion> 6 <type>pomtype> 7 <scope>importscope> 8 dependency> 9 10 <dependency> 11 <groupId>org.springframework.cloudgroupId> 12 <artifactId>spring-cloud-dependenciesartifactId> 13 <version>Hoxton.SR3version> 14 <type>pomtype> 15 <scope>importscope> 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.0modelVersion> 6 7 <groupId>com.testgroupId> 8 <artifactId>test-springcloudartifactId> 9 <version>1.0-SNAPSHOTversion> 10 <packaging>pompackaging> 11 12 13 <modules> 14 <module>test-springcloud-eureka-server8761module> 15 <module>test-springcloud-order8000module> 16 <module>test-springcloud-provider-payment8001module> 17 modules> 18 19 20 21 <properties> 22 <spring-boot.version>2.2.5.RELEASEspring-boot.version> 23 <spring-cloud.version>Hoxton.SR3spring-cloud.version> 24 25 <mybatis-spring-boot.version>2.1.2mybatis-spring-boot.version> 26 <mysql.version>8.0.12mysql.version> 27 <druid.version>1.1.21druid.version> 28 <lombok.version>1.18.12lombok.version> 29 <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> 30 <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding> 31 <java.version>1.8java.version> 32 properties> 33 34 35 36 <dependencyManagement> 37 <dependencies> 38 39 <dependency> 40 <groupId>org.springframework.bootgroupId> 41 <artifactId>spring-boot-dependenciesartifactId> 42 <version>${spring-boot.version}version> 43 <type>pomtype> 44 <scope>importscope> 45 dependency> 46 47 <dependency> 48 <groupId>org.springframework.cloudgroupId> 49 <artifactId>spring-cloud-dependenciesartifactId> 50 <version>${spring-cloud.version}version> 51 <type>pomtype> 52 <scope>importscope> 53 dependency> 54 55 56 57 58 59 60 61 62 63 64 <dependency> 65 <groupId>org.mybatis.spring.bootgroupId> 66 <artifactId>mybatis-spring-boot-starterartifactId> 67 <version>${mybatis-spring-boot.version}version> 68 dependency> 69 70 71 <dependency> 72 <groupId>mysqlgroupId> 73 <artifactId>mysql-connector-javaartifactId> 74 <version>${mysql.version}version> 75 dependency> 76 77 78 <dependency> 79 <groupId>com.alibabagroupId> 80 <artifactId>druid-spring-boot-starterartifactId> 81 <version>${druid.version}version> 82 dependency> 83 84 85 <dependency> 86 <groupId>org.projectlombokgroupId> 87 <artifactId>lombokartifactId> 88 <version>${lombok.version}version> 89 dependency> 90 91 92 <dependency> 93 <groupId>org.springframework.bootgroupId> 94 <artifactId>spring-boot-starter-testartifactId> 95 <version>${spring-boot.version}version> 96 <scope>testscope> 97 <exclusions> 98 <exclusion> 99 <groupId>org.junit.vintagegroupId> 100 <artifactId>junit-vintage-engineartifactId> 101 exclusion> 102 exclusions> 103 dependency> 104 dependencies> 105 dependencyManagement> 106 107 108 <build> 109 <finalName>${project.artifactId}finalName> 110 <plugins> 111 <plugin> 112 <groupId>org.apache.maven.pluginsgroupId> 113 <artifactId>maven-compiler-pluginartifactId> 114 <configuration> 115 <source>${java.version}source> 116 <target>${java.version}target> 117 configuration> 118 plugin> 119 <plugin> 120 <groupId>org.springframework.bootgroupId> 121 <artifactId>spring-boot-maven-pluginartifactId> 122 <version>${spring-boot.version}version> 123 <configuration> 124 <fork>truefork> 125 <addResources>trueaddResources> 126 configuration> 127 plugin> 128 plugins> 129 build> 130 project> 131 132 pom.xml
3、项目结构图如下:
搭建Eureka注册中心
即Eureka的服务端
1、在父项目上,new module 新建一个模块Eureka注册中心,及Eureka服务端 test-springboot-eureka-server8761
2、编写pom.xml文件
Eureka服务端依赖如下:
1 2 <dependency> 3 <groupId>org.springframework.cloudgroupId> 4 <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId> 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-springcloudartifactId> 7 <groupId>com.testgroupId> 8 <version>1.0-SNAPSHOTversion> 9 parent> 10 <modelVersion>4.0.0modelVersion> 11 12 <artifactId>test-springcloud-eureka-server8761artifactId> 13 14 <dependencies> 15 16 <dependency> 17 <groupId>org.springframework.cloudgroupId> 18 <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId> 19 dependency> 20 21 22 <dependency> 23 <groupId>org.springframework.bootgroupId> 24 <artifactId>spring-boot-starter-webartifactId> 25 dependency> 26 <dependency> 27 <groupId>org.springframework.bootgroupId> 28 <artifactId>spring-boot-starter-actuatorartifactId> 29 dependency> 30 <dependency> 31 <groupId>org.springframework.bootgroupId> 32 <artifactId>spring-boot-devtoolsartifactId> 33 <scope>runtimescope> 34 <optional>trueoptional> 35 dependency> 36 37 <dependency> 38 <groupId>org.springframework.bootgroupId> 39 <artifactId>spring-boot-starter-testartifactId> 40 <scope>testscope> 41 dependency> 42 43 dependencies> 44 45 <build> 46 <finalName>test-springcloud-eureka-server8761finalName> 47 build> 48 project>
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;
1、在父项目上,new module 新建一个模块支付模块,即Eureka客户端 test-springcloud-provider-payment8001
2、编写payment模块的pom.xml文件,引入Eureka 客户端依赖
1 2 <dependency> 3 <groupId>org.springframework.cloudgroupId> 4 <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId> 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-springcloudartifactId> 7 <groupId>com.testgroupId> 8 <version>1.0-SNAPSHOTversion> 9 parent> 10 <modelVersion>4.0.0modelVersion> 11 12 <artifactId>test-springcloud-provider-payment8001artifactId> 13 14 <dependencies> 15 16 17 <dependency> 18 <groupId>org.springframework.cloudgroupId> 19 <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId> 20 dependency> 21 22 23 <dependency> 24 <groupId>org.springframework.bootgroupId> 25 <artifactId>spring-boot-starter-webartifactId> 26 dependency> 27 <dependency> 28 <groupId>org.springframework.bootgroupId> 29 <artifactId>spring-boot-starter-actuatorartifactId> 30 dependency> 31 <dependency> 32 <groupId>org.springframework.bootgroupId> 33 <artifactId>spring-boot-starter-jdbcartifactId> 34 dependency> 35 <dependency> 36 <groupId>org.springframework.bootgroupId> 37 <artifactId>spring-boot-devtoolsartifactId> 38 <scope>runtimescope> 39 <optional>trueoptional> 40 dependency> 41 <dependency> 42 <groupId>org.mybatis.spring.bootgroupId> 43 <artifactId>mybatis-spring-boot-starterartifactId> 44 dependency> 45 <dependency> 46 <groupId>org.projectlombokgroupId> 47 <artifactId>lombokartifactId> 48 <optional>trueoptional> 49 dependency> 50 51 <dependency> 52 <groupId>mysqlgroupId> 53 <artifactId>mysql-connector-javaartifactId> 54 dependency> 55 56 <dependency> 57 <groupId>com.alibabagroupId> 58 <artifactId>druid-spring-boot-starterartifactId> 59 dependency> 60 <dependency> 61 <groupId>org.springframework.bootgroupId> 62 <artifactId>spring-boot-starter-testartifactId> 63 <scope>testscope> 64 dependency> 65 66 dependencies> 67 68 <build> 69 <finalName>test-springcloud-provider-payment8001finalName> 70 build> 71 project>
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 }
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>
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 }
8、新建一个service接口
1 public interface PaymentService { 2 // 插入 3 public int insert(Payment payment); 4 // 获取 5 public Payment getPaymentById(Long id); 6 }
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 }
10、编辑一个通用结果类CommonResult.java
1 /** 2 * 通用结果 3 * @param4 */ 5 @Data 6 @AllArgsConstructor 7 @NoArgsConstructor 8 public class CommonResult { 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 }
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 }
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-springcloudartifactId> 7 <groupId>com.testgroupId> 8 <version>1.0-SNAPSHOTversion> 9 parent> 10 <modelVersion>4.0.0modelVersion> 11 12 <artifactId>test-springcloud-order8000artifactId> 13 14 15 <dependencies> 16 17 18 <dependency> 19 <groupId>org.springframework.cloudgroupId> 20 <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId> 21 dependency> 22 23 24 <dependency> 25 <groupId>org.springframework.bootgroupId> 26 <artifactId>spring-boot-starter-webartifactId> 27 dependency> 28 <dependency> 29 <groupId>org.springframework.bootgroupId> 30 <artifactId>spring-boot-starter-actuatorartifactId> 31 dependency> 32 <dependency> 33 <groupId>org.springframework.bootgroupId> 34 <artifactId>spring-boot-devtoolsartifactId> 35 <scope>runtimescope> 36 <optional>trueoptional> 37 dependency> 38 39 <dependency> 40 <groupId>org.projectlombokgroupId> 41 <artifactId>lombokartifactId> 42 <optional>trueoptional> 43 dependency> 44 <dependency> 45 <groupId>org.springframework.bootgroupId> 46 <artifactId>spring-boot-starter-testartifactId> 47 <scope>testscope> 48 dependency> 49 50 dependencies> 51 52 <build> 53 <finalName>test-springcloud-order8000finalName> 54 build> 55 56 project>
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 }
7、编写通用返回类
1 @Data 2 @AllArgsConstructor 3 @NoArgsConstructor 4 public class CommonResult{ 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 }
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 CommonResultinsert(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 getPayment(@PathVariable("id") Long id){ 20 return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class); 21 } 22 }
9、启动order模块,查看Eureka注册中心
访问地址:http://localhost:8000/consumer/payment/get/1