SpringBoot整合SpringCloud


1. SpringCloud特点

SpringCloud专注于为典型的用例和扩展机制提供良好的开箱即用体验,以涵盖其他情况:

  • 分布式/版本化配置

  • 服务注册和发现 Eureka

  • 路由 Zuul

  • 服务到服务的呼叫

  • 负载均衡 Ribbon

  • 断路器 Hystrix

  • 分布式消息传递

2. 分布式系统的三个指标CAP

在介绍SpringCloud默认使用的注册中心前,先介绍分布式系统的三个指标,分别是:

  • Consistency:一致性,在分布式系统中,更新操作执行成功后所有的用户的读操作必须返回最新值;client写入,server同步至整个系统;

  • Availability:可用性,只要收到用户的请求,在一定的时间内服务器就必须给出回应,回应的结果可以是成功或是失败;

  • Partition tolerance:分区容错,即区间通信可能失败,在网络中断,消息丢失的情况下,仍对外提供服务;一般无法避免,可以认为CAP中的P总是成立

CAP定律说的是,在一个分布式计算机系统中,一致性C,可用性A,分区容错性P这三种保证无法同时得到满足,最多满足两个:

  1. 放弃P

为了避免分区容错性问题的发生,一种做法是将所有与事务相关的数据都放在一台服务器上,虽然不能保证100%系统不会出错,但是不会碰到由分区带来的负面效果,这样的做法会严重影响系统的扩展性。

  1. 放弃A

放弃可用性,一旦遇到分区容错故障,受到影响的服务器需要等待一定的时间,因此会导致在等待期间系统无法对外提供服务。

  1. 放弃C

这儿说的放弃一致性,并不是完全放弃数据的一致性,而是放弃数据的强一致性,而保留数据的最终一致性。以网络购物为例,对只剩下一件库存的商品,如果同时接受到了两份订单,那么较晚的订单将被告知商品告罄。

文中部分CAP理论摘自:https://www.cnblogs.com/hxsyl/p/4381980.html

3. Eureka

基本介绍

Eureka是SpringCloud官方推荐用于服务注册和发现,一个基于REST的服务

SpringBoot实现了Netflix OSS的集成,使用Eureka的原因之一是因为其可以利用Spring Cloud Netflix的其他组件:智能路由(Zuul)、客户端负载均衡(Ribbon)等

基本组成

Eureka由多个Instance(服务实例)组成,分为Eureka Server和Eureka Client

其中Eureka Client又可细分为:Service Provider、Service Consumer

  • Eureka Server:服务端,提供服务的注册和发现;

  • Eureka Client:客户端

    • Service Provider:服务提供方,将自身服务注册到Eureka,让消费方找到
    • Service Consumer:服务消费方,从Eureka获取注册服务列表,从而消费服务

Eureka和Zookeeper

1)由CAP理论的角度来看

Zookeeper:ZK保证CP,突出强一致性,但无法保证每次访问服务可用性,比如ZK会出现这样一种情况:当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举,在ZK选举leader期间整个ZK集群都是不可用的,这就导致了在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得ZK集群失去master节点是较大概率会发生的事儿,虽然服务最终会恢复,但是漫长的选举时间导致的注册长期不可用是难以容忍的。

Eureka:Eureka保证AP,Eureka在设计时就优先保证可用性。对于Eureka中的节点,每个节点都是平等的,几个节点挂掉也不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。但Eureka不保证强一致性,即查到的信息可能不是最新的。此外Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就会认为客户端和注册中心出现了网络故障,但会保证当前节点依然可用,不会像ZK导致整个注册服务瘫痪。

2)由节点分工的角度来看

Zookeeper:ZK集群中节点分为三类,承担不同的任务

  • Leader:事务请求唯一的调度者和处理者(除了查询请求)
  • Follower:处理非事务请求,参与Leader选举投票
  • Observer:处理非事务请求,但不参与Leader选举投票

Eureka:在Eureka集群中每个节点都是平等的,每个节点扮演相同的角色,它们通过相互注册的方式来感知对方的存在,当由注册消息时,它们会同步给集群内的其他节点

中文文档:https://www.springcloud.cc/spring-cloud-greenwich.html#_spring_cloud_netflix

4. SpringCloud Demo

Demo整体结构(父子项目)

  • api:Bean、DTO、POJO等以及Service接口

  • controller:服务消费方,前端交互

  • provider:服务提供方,服务实现

  • registry:服务注册中心

4.1 registry

1)pom.xml

关键点在于导入eureka服务端依赖以及SpringCloud依赖

  1. <dependencies>
  2. <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server -->
  3. <!-- eureka服务端 -->
  4. <dependency>
  5. <groupId>org.springframework.cloud</groupId>
  6. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  7. <version>2.2.5.RELEASE</version>
  8. </dependency>
  9. </dependencies>
  10. <dependencyManagement>
  11. <dependencies>
  12. <dependency>
  13. <groupId>org.springframework.cloud</groupId>
  14. <artifactId>spring-cloud-dependencies</artifactId>
  15. <version>Hoxton.SR6</version>
  16. <type>pom</type>
  17. <scope>import</scope>
  18. </dependency>
  19. </dependencies>
  20. </dependencyManagement>

2)application.properties

进行Eureka服务端的相关配置

  1. spring.application.name=SpringCloudDemoRegistry
  2. # server端口,自己喜欢
  3. server.port=8888
  4. # Eureka Server服务url以及默认zone,结尾必须eureka
  5. eureka.client.service-url.defaultZone= http://127.0.0.1:8888/eureka/
  6. # eureka的自我保护机制,k8s环境下建议false
  7. eureka.server.enable-self-preservation=false
  8. # false表示自己端就是注册中心,我的功能就是维护服务实例,不需要从server获取注册的服务信息
  9. eureka.client.fetch-registry=false
  10. # false表示不将自己注册到Eureka Server
  11. eureka.client.register-with-eureka=false

3)EurekaregistryApplication

使用@EnableEurekaServer激活相关配置,使registry模块作为注册中心Server

  1. @EnableEurekaServer //声明为注册中心服务端
  2. @SpringBootApplication
  3. public class EurekaregistryApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(EurekaregistryApplication.class, args);
  6. }
  7. }

4.2 api

1)entity

实体类以部门和用户信息为例,由于演示使用了Lombok省点代码,用于实现基本的CRUD

Department.class

  1. @Data
  2. @ToString
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class Department {
  6. private Long id;
  7. private Integer dId;
  8. private String dName;
  9. private Date updateTime;
  10. }

UserInfo.class

  1. @Data
  2. @ToString
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class UserInfo {
  6. private Long id;
  7. private Integer uId;
  8. private Integer dId;
  9. private String uName;
  10. private String uPhone;
  11. @Email(message = "非法邮件格式") //Validator格式校验
  12. private String uEmail;
  13. private String uAddress;
  14. private Date updateTime;
  15. private Department department;
  16. }

2)UserService

UserService为服务接口,声明需要提供和消费的方法,写了几个简单查询

  1. public interface UserService {
  2. /**
  3. * 判断用户是否存在,0为不存在,返回值与uId相等则存在
  4. * @param uId
  5. * @return
  6. */
  7. Integer userExist(Integer uId);
  8. /**
  9. * 获取用户个人基本信息
  10. * @param uId
  11. * @return
  12. */
  13. UserInfo getUserInfo(Integer uId);
  14. /**
  15. * 获取用户个人详情信息
  16. * @param uId
  17. * @return
  18. */
  19. UserInfo getUserDetailsInfo(Integer uId);
  20. }

4.3 provider

1)pom.xml

关键点是引入eureka客户端依赖、openfeign依赖、SpringCloud依赖

  1. <dependencies>
  2. <!-- Springboot的依赖省略... -->
  3. <dependency>
  4. <groupId>org.springframework.cloud</groupId>
  5. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework.cloud</groupId>
  9. <artifactId>spring-cloud-starter-openfeign</artifactId>
  10. </dependency>
  11. </dependencies>
  12. <dependencyManagement>
  13. <dependencies>
  14. <dependency>
  15. <groupId>org.springframework.cloud</groupId>
  16. <artifactId>spring-cloud-dependencies</artifactId>
  17. <version>Hoxton.SR6</version>
  18. <type>pom</type>
  19. <scope>import</scope>
  20. </dependency>
  21. </dependencies>
  22. </dependencyManagement>

2)application.properties

配置Eureka、Mybatis以及DataSource数据源等信息

  1. spring.application.name=SpringCloudDemoProvider
  2. # Server端口
  3. server.port=9999
  4. # Eureka服务url
  5. eureka.client.service-url.defaultZone= http://127.0.0.1:8888/eureka/
  6. eureka.client.register-with-eureka=true
  7. eureka.client.fetch-registry=true
  8. # Mybatis
  9. mybatis.mapper-locations= classpath:com.maziyao.provider.mapper/*.xml
  10. mybatis.type-aliases-package= com.maziyao.common.entity
  11. # DataSource数据源配置
  12. spring.datasource.type=com.zaxxer.hikari.HikariDataSource
  13. # DataSource
  14. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  15. spring.datasource.url=jdbc:mysql://localhost:3306/boot-demo?serverTimezone=UTC
  16. spring.datasource.username=root
  17. spring.datasource.password=root

3)EurekaproviderApplication

provider启动类使用@EnableEurekaClient声明为EurekaClient客户端,作为ServiceProvider

  1. @EnableEurekaClient
  2. @SpringBootApplication
  3. @EnableAspectJAutoProxy
  4. @MapperScan("com.maziyao.provider.mapper")
  5. @ComponentScan(basePackages = {
  6. "com.maziyao.provider.rest",
  7. "com.maziyao.provider.redis",
  8. "com.maziyao.provider.service",
  9. "com.maziyao.provider.config"
  10. })
  11. public class EurekaproviderApplication {
  12. public static void main(String[] args) {
  13. SpringApplication.run(EurekaproviderApplication.class, args);
  14. }
  15. }

4)service

UserServiceImpl作为UserService接口实现类,@Service用于标注业务层组件

自动注入mapper层的mapper接口并调用,mapper的SQL语句下面就略了,很简单

需要注意的是,对于数据访问层组件mapper,使用@Repository进行标注

  1. @Service("userService")
  2. public class UserServiceImpl implements UserService {
  3. @Autowired
  4. private UserMapper userMapper;
  5. @Override
  6. public Integer userExist(Integer uId) {
  7. return userMapper.userExist(uId);
  8. }
  9. @Override
  10. public UserInfo getUserInfo(Integer uId) {
  11. return userMapper.getUserInfo(uId);
  12. }
  13. @Override
  14. public UserInfo getUserDetailsInfo(Integer uId) {
  15. return userMapper.getUserDetailsInfo(uId);
  16. }
  17. }

5)rest

重点是rest包下的UserServer,要知道Eureka是一个基于REST的服务

使用@RestController标注并声明为userServer,这个是SpringBoot注解,用于标注控制层组件

  1. @RestController("userServer")
  2. public class UserServer {
  3. public static final Logger logger = LoggerFactory.getLogger(UserServer.class);
  4. @Autowired
  5. private UserService userService;
  6. @ResponseBody
  7. @RequestMapping(value = "/exist",method = RequestMethod.GET)
  8. public Integer existUserByUid(@RequestParam("uId")Integer uId){
  9. return userService.userExist(uId);
  10. }
  11. @ResponseBody
  12. @RequestMapping(value = "/userInfo",method = RequestMethod.GET)
  13. public UserInfo getUserInfo(@RequestParam("uId")Integer uId){
  14. return userService.getUserInfo(uId);
  15. }
  16. @ResponseBody
  17. @RequestMapping(value="/userDetailsInfo",method = RequestMethod.GET)
  18. public UserInfo getUserDetailsInfo(@RequestParam("uId")Integer uId){
  19. return userService.getUserDetailsInfo(uId);
  20. }
  21. }

4.4 consumer

1)pom.xml

在Controller的pom.xml中也需要导入EurekaClient的依赖,对于Provider和Controller都为Client

  1. <dependencies>
  2. <!-- SpringBoot依赖省略... -->
  3. <dependency>
  4. <groupId>org.springframework.cloud</groupId>
  5. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  6. <version>2.2.5.RELEASE</version>
  7. </dependency>
  8. <dependency>
  9. <groupId>org.springframework.cloud</groupId>
  10. <artifactId>spring-cloud-starter-openfeign</artifactId>
  11. <version>2.2.5.RELEASE</version>
  12. </dependency>
  13. </dependencies>

2)application.properties

在application.properties中配置Eureka相关信息

  1. spring.application.name=springCloudDemoController
  2. # Server端口
  3. server.port=8899
  4. # 注册中心url
  5. eureka.client.service-url.defaultZone= http://127.0.0.1:8888/eureka/
  6. eureka.client.register-with-eureka=true
  7. eureka.client.fetch-registry=true

3)EurekacontrollerApplication

与Provider的启动类一致,声明启动类为Eureka的客户端

并使用@EnableFeignClients开启Feign,声明性的web服务客户端

  1. @EnableEurekaClient
  2. @EnableFeignClients
  3. @SpringBootApplication
  4. @EnableAspectJAutoProxy
  5. @ComponentScan({
  6. "com.maziyao.controller.config",
  7. "com.maziyao.controller.controller",
  8. "com.maziyao.controller.rest"
  9. })
  10. public class EurekacontrollerApplication {
  11. public static void main(String[] args) {
  12. SpringApplication.run(EurekacontrollerApplication.class, args);
  13. }
  14. }

4)rest

controller作为前端交互层,即控制层,此处UserClient声明调用方法

使用@FeignClient声明服务提供方在application.properties中配置的spring.application.name

以及绑定服务提供方对应rest包下的UserServer类的@RestController("userServer")

  1. @FeignClient(name = "springCloudDemoProvider",contextId = "userServer")
  2. public interface UserClient {
  3. @ResponseBody
  4. @RequestMapping(value = "/exist",method = RequestMethod.GET)
  5. public Integer existUserByUid(@RequestParam("uId")Integer uId);
  6. @ResponseBody
  7. @RequestMapping(value = "/userInfo",method = RequestMethod.GET)
  8. public UserInfo getUserInfo(@RequestParam("uId")Integer uId);
  9. @ResponseBody
  10. @RequestMapping(value="/userDetailsInfo",method = RequestMethod.GET)
  11. public UserInfo getUserDetailsInfo(@RequestParam("uId")Integer uId);
  12. }

5)UserController

控制层,使用@RestController标注,并注入UserClient进行调用

  1. @RestController
  2. public class UserController {
  3. private static final Logger logger = LoggerFactory.getLogger(UserController.class);
  4. @Autowired
  5. private UserClient userClient;
  6. @ResponseBody
  7. @RequestMapping(value = "/exist",method = RequestMethod.GET)
  8. public Integer existUserByUid(@RequestParam("uId") Integer uId){
  9. return userClient.existUserByUid(uId);
  10. }
  11. @ResponseBody
  12. @RequestMapping(value = "/userInfo",method = RequestMethod.GET)
  13. public UserInfo getUserInfoByUid(@RequestParam("uId")Integer uId){
  14. return userClient.getUserInfo(uId);
  15. }
  16. @ResponseBody
  17. @RequestMapping(value = "/userDetailsInfo",method = RequestMethod.GET)
  18. public UserInfo getUserDetailsInfoByUid(@RequestParam("uId")Integer uId){
  19. return userClient.getUserDetailsInfo(uId);
  20. }
  21. }

4.5 POSTMAN一下

注意:最后记得mvn install,需要先将registry运行起来,再分别运行provider和controller

启动registry:

启动provider:

启动consumer:

result:

Java-SpringBoot整合SpringCloud的更多相关文章

  1. SpringBoot整合SpringCloud搭建分布式应用

    什么是SpringCloud? SpringCloud是一个分布式的整体解决方案.SpringCloud为开发者提供了在分布式系统中快速构建的工具,使用SpringCloud可以快速的启动服务或构建应 ...

  2. java springboot整合zookeeper入门教程(增删改查)

    java springboot整合zookeeper增删改查入门教程 zookeeper的安装与集群搭建参考:https://www.cnblogs.com/zwcry/p/10272506.html ...

  3. 33、springboot整合springcloud

    Spring Cloud Spring Cloud是一个分布式的整体解决方案.Spring Cloud 为开发者提供了在分布式系统 (配置管理,服务发现,熔断,路由,微代理,控制总线,一次性token ...

  4. SpringCloud:SpringBoot整合SpringCloud项目

    划分模块 这里我划分了四个模块 Common: 存放bean和Dao模块 Consumer: 消费者模块,提供对外暴露接口服务 EurekaServer: Eureka注册中心模块,主要用于启动注册中 ...

  5. Rabbitmq基本使用 SpringBoot整合Rabbit SpringCloud Stream+Rabbit

    https://blog.csdn.net/m0_37867405/article/details/80793601 四.docker中使用rabbitmq 1. 搭建和启动 使用地址:rabbitm ...

  6. SpringBoot分布式篇Ⅷ --- 整合SpringCloud

    SpringCloud是一个分布式的整体解决方案.Spring Cloud为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性token,全局锁,leader选举.分布 ...

  7. java操作mongodb & springboot整合mongodb

    简单的研究原生API操作MongoDB以及封装的工具类操作,最后也会研究整合spring之后作为dao层的完整的操作. 1.原生的API操作 pom.xml <!-- https://mvnre ...

  8. Java学习之SpringBoot整合SSM Demo

    背景:在Java Web中Spring家族有着很重要的地位,之前JAVA开发需要做很多的配置,一堆的配置文件和部署调试一直是JavaWeb开发中的一大诟病,但现在Spring推出了SpringBoot ...

  9. springboot整合mybatis的时候报错Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

    今天闲来无事,学习springboot整合mybatis,在bilibili看视频学的,视频中在dao层的interface上面加上org.apache.ibatis.annotations.Mapp ...

随机推荐

  1. Linux常见问题解决方案

    1.Kali2020添加BCM43142的网卡驱动 来源:https://www.fujieace.com/kali-linux/wifi-drive.html 我只是执行了第三步:安装网卡驱动,即: ...

  2. Goland 这些技巧,学会开发效率翻倍!

    hi, 大家好,我是 hhf. <Goland 这些实操技巧,你可能还不会!>介绍了日常开发中一些比较好用的技巧.本篇文章继续介绍一些其他比较好用的技巧. 自定义结构 tag Goland ...

  3. JavaScript学习03(函数)

    函数 函数定义 JavaScript 函数是通过 function 关键词定义的. 声明定义 function functionName(parameters) { 要执行的代码 } 被声明的函数不会 ...

  4. 012 PCIe总线的基础知识

    一.PCIe总线的基础知识 与PCI总线不同,PCIe总线使用端到端的连接方式,在一条PCIe链路的两端只能各连接一个设备,这两个设备互为是数据发送端和数据接收端.PCIe总线除了总线链路外,还具有多 ...

  5. 谈谈 Nginx 那点事【一】

    为什么突然决定总结Nginx ? 不知不觉8月份又要过完了,时间真是个无情的崽种. 写Nginx 首先,主要源于最近项目部署工作中和公司技术中心的人对接部署相关事宜流程太繁琐了.每个部门有各自的工作安 ...

  6. 获取访问者真实ip地址?我觉得不可能

    我们真的能通过请求来获取用户真实的ip地址嘛? 答案是不能,如果能,肯定是我学的不够深入,欢迎交流指正. 那么写这篇文章的意义是什么?我们接着往下看. IP地址相当于电脑在网络上的身份证,但事实上IP ...

  7. Centos7 出现Welcome to emergency mode!【紧急模式】

    Centos7 出现Welcome to emergency mode![紧急模式] 做mount挂载时,修改了  /etc/fstab 文件,导致Centos7重启时出现如下图所示错误:   输入r ...

  8. Java String 综述(上篇)

    摘要: Java 中的 String类 是我们日常开发中使用最为频繁的一个类,但要想真正掌握的这个类却不是一件容易的事情.笔者为了还原String类的真实全貌,先分为上.下两篇博文来综述Java中的S ...

  9. Timer和TimerTask(转载)

    下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了r ...

  10. Mysql的undo、redo、binlog的区别

      与不同引擎的关系 核心作用 生命周期   日志类型 undo log 属于innodb引擎独有 回滚,保证事务的"原子性",事务日志  事务开始前,以类似"快照&qu ...