`

跟我学Spring Cloud(Finchley版)-02-构建分布式应用

 
阅读更多

说明:SpringCloud系列笔者自学系列,学习来源是周立的博客  http://www.itmuch.com/ 。而此处转载其博客只是为了方便自己以后的学习。

本篇来源 http://www.itmuch.com/spring-cloud/finchley-2/

 

 

上一节说过,Spring Cloud是一个快速构建分布式应用的工具集。本节,我们就来编写一个简单的分布式应用,并探讨这个分布式应用有哪些问题。

 

服务消费者 & 提供者

 

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

 

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

 

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

 

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

 

图3-1 服务提供者与服务消费者

 

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

 

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 使用网页版)创建应用,它会给你生成项目的依赖以及项目的骨架。后续,笔者会以番外的形式更新相关教程。

 

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

 

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

    
    
    <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.itmuch.cloud</groupId>
      <artifactId>microservice-simple-provider-user</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <!-- 引入spring boot的依赖 -->
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
      </parent>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- 引入H2数据库,一种内嵌的数据库,语法类似MySQL -->
        <dependency>
          <groupId>com.h2database</groupId>
          <artifactId>h2</artifactId>
        </dependency>
        <!-- 引入Lombok -->
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <optional>true</optional>
        </dependency>
      </dependencies>
    
      <!-- 引入spring cloud的依赖,不能少,主要用来管理Spring Cloud生态各组件的版本 -->
      <dependencyManagement>
        <dependencies>
          <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR2</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>
        </dependencies>
      </dependencyManagement>
    
      <!-- 添加spring-boot的maven插件,不能少,打jar包时得用 -->
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    </project>

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

    WARNING

    TIPS

  • 创建实体类:

    
    
    @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;
    }
  • 创建DAO:

    
    
    @Repository
    public interface UserRepository extends JpaRepository<User, Long> {
    }
  • 创建Controller:

    
    
    @RequestMapping("/users")
    @RestController
    public class UserController {
      @Autowired
      private UserRepository userRepository;
    
      @GetMapping("/{id}")
      public Optional<User> findById(@PathVariable Long id) {
        return this.userRepository.findById(id);
      }
    }

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

  • 编写启动类:

    
    
    @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不能共存
       * 原因详见:
       * https://github.com/spring-projects/spring-boot/issues/13042
       * https://github.com/spring-projects/spring-boot/issues/13539
       *
       * @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,来简化开发。

    在启动时,我们使用了ApplicationRunner init(UserRepository repository) 初始化了三条数据,分别是张三、李四、王五。@Bean 则是一个方法注解,作用是实例化一个Bean并使用该方法的名称命名。类似于XML配置方式的<bean id="init" class="...ApplicationRunner"/>

  • 编写配置文件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的用户信息。

 

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

  • 加依赖:

    
    
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  • 创建实体类:

    
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
      private Long id;
      private String username;
      private String name;
      private Integer age;
      private BigDecimal balance;
    }
  • 创建启动类:

    
    
    @SpringBootApplication
    public class ConsumerMovieApplication {
      @Bean
      public RestTemplate restTemplate() {
        return new RestTemplate();
      }
    
      public static void main(String[] args) {
        SpringApplication.run(ConsumerMovieApplication.class, args);
      }
    }
  • 创建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。

  • 编写配置文件application.yml 

    
    
    server:
      port: 8010

 

拓展阅读

 

本文使用RestTemplate实现了基于HTTP的远程调用,事实上,Spring 5开始,WebFlux提供了Reactive的Web Client:WebClinet 使用方式和RestTemplate基本类似,但性能更强,吞吐更好。有兴趣的可前往https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/web-reactive.html#webflux-client-builder 了解。在这里,笔者对WebClient做了一些简单的封装,也可关注:https://github.com/itmuch/thor-test/blob/master/src/main/java/com/itmuch/thor/httpclient/WebClientUtil.java

 

测试

 

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

 


{"id":1,"username":"account1","name":"张三","age":20,"balance":100.00}

 

存在的问题

 

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

 

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

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

    你可能会质疑:用户微服务地址为什么会变,让它保持不变就行了啊,这不是问题。这里举两个例子:

    例1:如果你用Docker,那么地址几乎每次启动都会变……

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

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

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

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

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

 

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

 

配套代码

 

 

相关文章

 

 

 

 

分享到:
评论

相关推荐

    spring-cloud-config + spring-cloud-bus-amqp实现分布式集群配置动态更新

    总结来说,Spring Cloud Config 和 Spring Cloud Bus AMQP 的组合,借助于RabbitMQ,为我们提供了一个强大的分布式配置管理和动态更新机制。通过这种解决方案,我们可以高效地管理大规模微服务集群的配置,提高系统...

    springCloud项目-分布式项目仓库

    springCloud项目-分布式项目仓库springCloud项目-分布式项目仓库springCloud项目-分布式项目仓库springCloud项目-分布式项目仓库springCloud项目-分布式项目仓库springCloud项目-分布式项目仓库springCloud项目-...

    Spring Cloud Finchley.SR1-Spring Cloud 手册-Spring Cloud 文档

    在接下来的内容中,我将详细描述标题《Spring Cloud Finchley.SR1-Spring Cloud 手册-Spring Cloud 文档》与《Spring Cloud 2.x手册-Spring Cloud 2.x 文档》以及标签“springCloud spring 微服务”中涉及的知识点。...

    spring-cloud-dependencies-Finchley.SR2.pom

    spring cloud的pom文件,解决maven无法导入依赖的问题,spring-cloud-dependencies-Finchley.SR2.pom文件

    springcloud-Netflix-eureka demo 可做参考

    在分布式系统中,Spring Cloud是实现微服务架构的重要工具,而Spring Cloud Netflix Eureka则是Spring Cloud生态中的服务发现组件。本项目"springcloud-Netflix-eureka demo"提供了一个基于Spring Boot搭建的基础...

    Ideal版SpringCloud框架参考---分布式微服务架构参考

    在IT行业中,Spring Cloud是一个广泛使用的开源框架,用于构建分布式微服务系统。它基于Spring Boot,使得开发人员能够轻松地创建和管理云原生应用程序。本文将深入探讨标题" Ideal版SpringCloud框架参考---分布式微...

    springcloud-learning-master.zip springcloud学习合集

    SpringCloud是中国Java开发者中最受欢迎的微服务框架之一,它提供了构建分布式系统所需的众多工具和服务,如服务发现、负载均衡、断路器、API网关、配置中心等。本压缩包"springcloud-learning-master.zip"是一个...

    spring-cloud-starter-stream-rabbit MQ使用规范

    &lt;artifactId&gt;spring-cloud-starter-stream-rabbit ``` 在 `application.properties` 文件中,我们可以添加以下配置: ```properties spring.rabbitmq.host=47.92.108.148 spring.rabbitmq.port=6672 spring....

    若依SpringCloud微服务版-傻瓜式教程模式

    【若依SpringCloud微服务版-傻瓜式教程模式】是一个面向初学者的教程,旨在帮助没有微服务架构经验的人快速上手搭建基于Spring Cloud的若依(RuoYi)微服务系统。若依是一个开源的Java管理框架,集成了Vue前端和Spring...

    springcloud-learning-master.zip

    SpringCloud是中国Java开发者广泛采用的微服务框架,它基于Spring Boot进行快速构建分布式系统中的配置管理、服务发现、断路器、智能路由、微代理、控制总线等核心功能。本压缩包“springcloud-learning-master.zip...

    SpringCloud-Finchley.SR1-Ribbon客户端负载均衡demo

    良心demo,可以再学习的过程中参考一下,官网的教程是真的需要好好琢磨的,这个可以作为辅助参考,demo采用的版本均为最新版本:springcloud2.0-Finchley.SR1版本,大神提醒我一句学习springcloud不要想的太复杂,...

    springcloud-eureka-server.zip

    本文将围绕"springcloud-eureka-server.zip"这个项目,深入探讨SpringCloud Eureka Server的核心功能、配置优化以及实际应用。 一、Eureka Server概述 Eureka是Netflix开源的一个基于REST的服务,用于定位服务,以...

    spring-cloud-demo-master.zip

    《Spring Cloud实战:基于"spring-cloud-demo-master.zip"的入门指南》 在现代微服务架构中,Spring Cloud作为主流的工具集,为开发者提供了构建分布式系统的服务发现、配置管理、断路器等一系列功能。本篇文章将...

    spring-cloud-examples-master

    《Spring Cloud实战详解:基于spring-cloud-examples-master的深度解析》 在当今的软件开发领域,微服务架构已经成为主流趋势,而Spring Cloud作为Java生态中的微服务治理框架,深受开发者们的喜爱。本篇文章将深入...

    spring-cloud-alibaba,spring cloud alibaba为阿里中间件的分布式解决方案提供了一站式的应用开发解决方案。.zip

    Spring Cloud Alibaba 是一个由阿里巴巴维护的开源项目,它为开发者提供了在分布式系统(如微服务、云应用)中实现各种经典设计模式的工具集。该项目致力于简化开发过程,使开发者可以快速构建一些常见的分布式系统...

    spring-cloud项目_springcloud_springcloud项目_springcloud_spring-clou

    Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具集,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)...

    spring-cloud-starter-netflix-zuul.zip已经闭源的jar包,pom

    Spring Cloud Gateway作为Spring Cloud的下一代API网关,基于Spring Framework 5、Project Reactor和Spring WebFlux构建,提供了更高效、更灵活的路由能力,并且有更好的性能表现。同时,它还集成了Spring Cloud的...

    基于Spring Cloud(Finchley版本)架构体系

    Spring Cloud Finchley是Spring Cloud的一个重要版本,它提供了一套微服务开发的工具集,用于构建分布式系统,如服务发现、配置管理、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式...

    hello-spring-cloud-alibaba-dependencies.zip

    标题中的"hello-spring-cloud-alibaba-dependencies.zip"是一个压缩包文件,暗示了它包含了与Spring Cloud Alibaba相关的依赖。Spring Cloud Alibaba是阿里巴巴提供的一个微服务框架,它将一系列优秀的中间件整合到...

Global site tag (gtag.js) - Google Analytics