Spring Cloud Finchley版-02-构建分布式应用

服务消费者 & 提供者

本书使用服务提供者与服务消费者来描述微服务之间的调用关系。下表解释了服务提供者与服务消费者。

表-服务提供者与服务消费者

[td]

名词

定义

服务提供者 服务的被调用方(即:为其他服务提供服务的服务) 服务消费者 服务的调用方(即:依赖其他服务的服务)

以电影售票系统为例。如图,用户向电影微服务发起了一个购票的请求。在进行购票的业务操作前,电影微服务需要调用用户微服务的接口,查询当前用户的余额是多少、是不是符合购票标准等。在这种场景下,用户微服务就是一个服务提供者,电影微服务则是一个服务消费者。

围绕该场景,先来编写一个用户微服务,然后编写一个电影微服务。

TIPS

服务消费者和服务提供者描述的只是微服务之间的调用关系,一般成对出现。例如本文,用户微服务是是电影微服务的服务提供者,电影微服务是用户微服务的服务消费者。很多初学者和笔者交流时,会描述提供者如何如何……仿佛消费者和提供者是微服务的固有属性,这是不对的——例如A调用B,B调用C,那么B相对A就是提供者,B相对C就消费者。

Spring Boot/Spring Cloud应用开发套路

Spring Boot/Spring Cloud时代后,应用开发基本遵循三板斧:

  • 加依赖
  • 加注解
  • 写配置

至于你的业务代码,该怎么写还怎么写。

TIPS
对于懒人,可使用Spring Initilizr(IDEA、Spring Tool Suite等IDE上均有集成,也可在http://start.spring.io 使用网页版)创建应用,它会给你生成项目的依赖以及项目的骨架。后续,笔者会以番外的形式更新相关教程。

编写服务提供者【用户微服务】

1 创建一个Maven项目,依赖如下:

其中, spring-boot-starter-web 提供了Spring MVC的支持; spring-boot-starter-data-jpa 提供了Spring Data JPA的支持; h2 是一种内嵌的数据库,语法和MySQL类似(笔者实在没有动力为了简单的演示再写一大堆内容去演示怎么安装MySQL数据库); lombok 则是一款开发利器,可以帮助你简化掉N多冗余代码。

WARNING

TIPS

2 创建实体类:

  • @Entity
  • @Data
  • @NoArgsConstructor
  • @AllArgsConstructor
  • public class User {
  • @Id
  • @GeneratedValue(strategy = GenerationType.AUTO)
  • private Long id;
  • @Column
  • private String username;
  • @Column
  • private String name;
  • @Column
  • private Integer age;
  • @Column
  • private BigDecimal balance;
  • }

3 创建DAO:

  • @Repository
  • public interface UserRepository extends JpaRepository
  • }

4 创建Controller:

  • @RequestMapping(“/users”)
  • @RestController
  • public class UserController {
  • @Autowired
  • private UserRepository userRepository;
  • @GetMapping(“/{id}”)
  • public Optional
  • return this.userRepository.findById(id);
  • }
  • }

其中, @GetMapping,是Spring 4.3提供的新注解。它是一个组合注解,等价于 @RequestMapping(method=RequestMethod.GET),用于简化开发。同理还有 @PostMapping、 @PutMapping、 @DeleteMapping、 @PatchMapping等。

5 编写启动类:

  • @SpringBootApplication
  • public class ProviderUserApplication {
  • public static void main(String[] args) {
  • SpringApplication.run(ProviderUserApplication.class, args);
  • }
  • /**
    • 初始化用户信息
    • 注:Spring Boot2不能像1.x一样,用spring.datasource.schema/data指定初始化SQL脚本,否则与actuator不能共存
    • 原因详见:
  • *
    • @param repository repo
    • @return runner
  • */
  • @Bean
  • ApplicationRunner init(UserRepository repository) {
  • return args -> {
  • User user1 = new User(1L, “account1”, “张三”, 20, new BigDecimal(100.00));
  • User user2 = new User(2L, “account2”, “李四”, 28, new BigDecimal(180.00));
  • User user3 = new User(3L, “account3”, “王五”, 32, new BigDecimal(280.00));
  • Stream.of(user1, user2, user3)
  • .forEach(repository::save);
  • };
  • }
  • }

@SpringBootApplication是一个组合注解,它整合了 @Configuration、 @EnableAutoConfiguration和 @ComponentScan注解,并开启了Spring Boot程序的组件扫描和自动配置功能。在开发Spring Boot程序的过程中,常常会组合使用 @Configuration、 @EnableAutoConfiguration和 @ComponentScan等注解,所以Spring Boot提供了 @SpringBootApplication,来简化开发。

在启动时,我们使用了 ApplicationRunnerinit(UserRepositoryrepository) 初始化了三条数据,分别是张三、李四、王五。 @Bean 则是一个方法注解,作用是实例化一个Bean并使用该方法的名称命名。类似于XML配置方式的

6 编写配置文件 application.yml :

  • server:
  • 指定Tomcat端口

  • port: 8000
  • spring:
  • jpa:
  • 让hibernate打印执行的SQL

  • show-sql: true
  • logging:
  • level:
  • root: INFO
  • 配置日志级别,让hibernate打印出执行的SQL参数

  • org.hibernate: INFO
  • org.hibernate.type.descriptor.sql.BasicBinder: TRACE
  • org.hibernate.type.descriptor.sql.BasicExtractor: TRACE

传统Web应用开发中,常使用properties格式文件作为配置文件。Spring Boot以及Spring Cloud支持使用properties或者yml格式的文件作为配置文件。

yml文件格式是YAML(Yet Another Markup Language)编写的文件格式,YAML和properties格式的文件可互相转换,例如本节中的application.yml,就等价于如下的properties文件:

  • server.port=8000
  • spring.jpa.show-sql=true
  • logging.level.root=INFO
  • logging.level.org.hibernate=INFO
  • logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
  • logging.level.org.hibernate.type.descriptor.sql.BasicExtractor=TRACE

从中不难看出,YAML比properties结构清晰;可读性、可维护性也更强,并且语法非常简洁。因此,本书使用YAML格式作为配置文件。但,yml有严格的缩进,并且key与value之间使用 : 分隔,冒号后的空格不能少,请大家注意。

测试

访问 http://localhost:8000/users/1 ,可获得结果:

  • {“id”:1,”username”:”account1″,”name”:”张三”,”age”:20,”balance”:100.00}

编写服务消费者【电影微服务】

我们已经编写了一个服务提供者(用户微服务),本节来编写一个服务消费者(电影微服务)。该服务非常简单,它使用RestTemplate调用用户微服务的API,从而查询指定id的用户信息。

1 创建一个Maven项目,ArtifactId是 microservice-simple-consumer-movie 。

2 加依赖:

*

3 创建实体类:

  • @Data
  • @AllArgsConstructor
  • @NoArgsConstructor
  • public class User {
  • private Long id;
  • private String username;
  • private String name;
  • private Integer age;
  • private BigDecimal balance;
  • }

4 创建启动类:

  • @SpringBootApplication
  • public class ConsumerMovieApplication {
  • @Bean
  • public RestTemplate restTemplate() {
  • return new RestTemplate();
  • }
  • public static void main(String[] args) {
  • SpringApplication.run(ConsumerMovieApplication.class, args);
  • }
  • }

5 创建Controller:

  • @RequestMapping(“/movies”)
  • @RestController
  • public class MovieController {
  • @Autowired
  • private RestTemplate restTemplate;
  • @GetMapping(“/users/{id}”)
  • public User findById(@PathVariable Long id) {
  • // 这里用到了RestTemplate的占位符能力
  • User user = this.restTemplate.getForObject(“http://localhost:8000/users/{id}”, User.class, id);
  • // …电影微服务的业务…

  • return user;

  • }
  • }

由代码可知,Controller使用RestTemplate调用用户微服务的RESTful API。

6 编写配置文件 application.yml :

  • server:
  • port: 8010

拓展阅读
本文使用RestTemplate实现了基于HTTP的远程调用,事实上,Spring 5开始,WebFlux提供了Reactive的Web Client: WebClinet ,使用方式和RestTemplate基本类似,但性能更强,吞吐更好。有兴趣的可前往https://docs.spring.io/spring/do … flux-client-builder 了解。在这里,笔者对WebClient做了一些简单的封装,也可关注:https://github.com/itmuch/thor-t … /WebClientUtil.java

测试

访问: http://localhost:8010/movies/users/1 ,结果如下:

  • {“id”:1,”username”:”account1″,”name”:”张三”,”age”:20,”balance”:100.00}

存在的问题

至此,我们已经实现了这个最简单的分布式应用,应用之间通过HTTP通信。代码非常简单,但这些简单的代码里,存在着若干问题:

1 应用没有监控,没有画板,一切指标都没有。在这个Growth Hack逐渐成为主流的时代,不弄个Dashboard把系统压力、QPS、CPU、内存、日活啥的可视化,你好意思出来混吗……

2 地址硬编码问题——电影微服务中将用户微服务的地址写死,如果用户微服务地址发生变化,难道要重新上线电影微服务吗?

你可能会质疑:用户微服务地址为什么会变,让它保持不变就行了啊,这不是问题。这里举两个例子:
例1:如果你用Docker,那么地址几乎每次启动都会变……

例2:你之前用的是TXYun,后来你想把用户微服务迁移到Aliyun。这个时候IP就会发生变化。我相信你不会乐意找到哪些服务调用了用户微服务的接口,然后所有调用用户微服务的服务统一修改地址……

3 负载均衡如何考虑?难道得在电影微服务和用户微服务之间加个NGINX做负载均衡吗?听起来是可行的,但如果有10000+服务(这并不夸张,我司的微服务数目是这个数字乘以N,N >= m,哈哈哈)那这个NGINX的配置得有多复杂……

4 服务之间没有容错机制,相信对技术有激情的你已经不止一次听过容错、降级、fallback、回退之类的词汇。

5 如果应用发生故障,你怎么迅速找到问题所在?

6 用户认证和授权呢?被狗吃了吗?

如上词汇,你可能看得懂,你也可能看不懂。没有关系,请继续阅读,笔者将会用通俗的语言去描述,在你看完本系列后,你会知道,原来那些所谓的高大上的理论、术语、技术,原来也就是这么回事儿。

配套代码

GitHub:

  • https://github.com/eacdy/spring-cloud-study/tree/master/2018-Finchley/microservice-simple-provider-user
  • https://github.com/eacdy/spring-cloud-study/tree/master/2018-Finchley/microservice-simple-consumer-movie

Gitee:

  • https://gitee.com/itmuch/spring-cloud-study/tree/master/2018-Finchley/microservice-simple-provider-user
  • https://gitee.com/itmuch/spring-cloud-study/tree/master/2018-Finchley/microservice-simple-consumer-movie
  • 更多免费技术资料可关注:annalin1203

Original: https://www.cnblogs.com/zhuxiaopijingjing/p/12985729.html
Author: 幽暗森林之猪大屁
Title: Spring Cloud Finchley版-02-构建分布式应用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/540611/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 利用 Spring Boot 中的 @ConfigurationProperties,优雅绑定配置参数

    使用 @Value(“${property}”) 注释注入配置属性有时会很麻烦,尤其是当你使用多个属性或你的数据是分层的时候。 Spring Boot 引入…

    Java 2023年5月30日
    082
  • Golang中的defer、panic与recover关键字

    一、defer关键字 1.defer关键字定义了在当前函数生命周期结束之前触发的一种机制,类似于C++中的析构函数,Java中的final关键字。如在main函数中定义: defe…

    Java 2023年6月13日
    064
  • 7-枚举和注解

    枚举类的理解:类的对象只有有限个,确定的。我们称此类为枚举类 当需要定义一组常量时,强烈建议使用枚举类 如果枚举类中只一个对象,则可以作为单例模式的实现方式。 1.如何自定义枚举类…

    Java 2023年6月7日
    064
  • Java源码赏析(四)Java常见注解

    元注解 @Target :标识注解的目标,默认为所有 * ElementType.TYPE(用于类) * ElementType.FIELD(用于域,包括enum) * Eleme…

    Java 2023年6月8日
    072
  • / 和%的区别

    / : 就是数学中的除号,如果是小数,会取整数部分 %: 当左边的数字小于右边时,取模是左边的数字 相同是0 当左边的数字大于右边时,取的是余数 posted @2022-05-1…

    Java 2023年6月6日
    0132
  • Windows 使用 keytool 导入证书到 jdk 密钥库

    确定 java 安装路径, 一般情况下存在于 C:\Program Files\Java\jdk_xxx,根据自身电脑安装情况而定。 管理员权限打开终端 cmd , 进入 C:\P…

    Java 2023年6月7日
    074
  • Spring(五):IoC创建对象的方式

    一、bean被创建的时间 考虑一个问题,我们都知道spring通过xml的配置创建bean,那么bean是什么时间被创建的呢?是在我们getBean()的时候创建的吗? 我们来做一…

    Java 2023年6月15日
    088
  • Kotlin学习快速入门(8)—— 委托

    原文地址:Kotlin学习快速入门(8)—— 属性委托 – Stars-One的杂货小窝委托其实是一种设计模式,但Kotlin把此特性编写进了语法中,可以方便开发者快速…

    Java 2023年6月13日
    085
  • 找出JVM中最耗cpu的线程

    1、 top命令查找出cpu最高的java进程 pid 2、 top -Hp 命令找出进程内最耗线程的 pid 3、获取到上一步线程的 pid后 将 pid 16进制输出 4 使用…

    Java 2023年6月16日
    079
  • Eureka详解系列(三)–探索Eureka强大的配置体系

    通过前面的两篇博客,我们知道了:什么是 Eureka?为什么使用 Eureka?如何使用 Eureka?今天,我们开始来研究 Eureka 的源码,先从配置部分的源码开始看,其他部…

    Java 2023年6月13日
    074
  • 事务、事务隔离级别、三读问题

    一、事务 二、事务隔离级别 三、三读问题 一、事务 事务定义:一组数据操作要么全成功,要么全失败。事务四大特性:ACID原子性:要么全成功,要么全失败。一致性:事务执行的结果必须是…

    Java 2023年6月8日
    059
  • vue3进阶学习

    vue3进阶学习 官方网站:https://v3.vuejs.org/中文文档: https://staging-cn.vuejs.org/guide/introduction.h…

    Java 2023年6月5日
    0100
  • Spring 依赖注入循环依赖问题解决

    项目中可能会出现两个service需要相互调用的情况,两个service相互调用会造成bean循环依赖,Spring在应用程序上下文启动时就会去创建所有的单例bean对象,从而导致…

    Java 2023年6月7日
    070
  • JVM集合之开篇点题

    大家在平时的开发过程中是否遇到过 StackOverflowError、 OutOfMemoryError等类似的内存溢出错误呢?大家又是怎么解决这个问题的?再来,大家在面试过程中…

    Java 2023年6月5日
    084
  • CSDN博客迁移至博客园

    CSDN博客迁移 由于早期在csdn中自定义了博客域名地址Xc_xdd,后期由于csdn由于我的id名称涉及政治敏感,未提前告知用户,且不给id修改机会。将我博客永久封禁,不可解封…

    Java 2023年6月8日
    062
  • 从双重校验锁进一步理解synchronized和volatile

    并发编程中的四个问题:可见性、原子性、有序性、指令重排对于 synchronized和 volatile首先我们知道: synchronized可以保证原子性、有序性、可见性; v…

    Java 2023年6月13日
    069
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球