Spring cloud 理论+实践+解析 手摸手带你一起搭建(一 什么是微服务)

本身,在学习之前,我也是对spring cloud 比较陌生,也不理解什么所谓的注册中心等内容。学完之后就想从一个小白的角度去讲,去着手了解这个spring cloud 是什么东西,一个篇章可能介绍不完,也没法完整地去解释这是个什么内容,因此我想通过几篇连载去讲述,当然会有很多不足,因此也欢迎大家私聊我给出意见。


前言

大家可能在此之前多多少少都听说过微服务。微服务在最近几年也是很火,如果你不会微服务都可能都显得不那么主流了。甚至有很多团队强行为了微服务而去微服务,最终写成一个大型的分布式单体应用,就是改造后的系统既没有微服务的快速扩容,灵活发布的特性,也让原本的单体应用失去了方便开发,部署容易的特性(项目拆为多份,开发部署复杂度都提高了),不得不说是得不偿失。因此我们在了解SpringCloud 前非常有必要了解这是个什么东西,我们为什么使用他?怎么样设计更加合理。


一、微服务是什么?

首先呢,我认为了解一个陌生的东西,更好的是通过代码,通过实践去了解更为深刻,也更好了解。
不需要用多么专业的术语,因为我在一开始看到这些专业的术语我是懵逼的,虽然那些术语让人觉得很装逼,但是我更希望知道这是个什么东西更为重要。那么本次面向的读者呢也是刚要了解这部分内容的朋友,如果你是大佬,emmm,这文章肯定有很多不足,可以私聊我帮忙指点。
在这里插入图片描述
上面这是我在别的地方找到的一张图,可以清楚地看到这是个逐步解耦的过程。
解耦不解耦,怎么理解,怎么解释?微服务是什么样?
解耦就是分开,怎么分开,先看下没分开前,我们的工程目录是什么样。
在这里插入图片描述
大家注意看这个service、handler、mapper的包,此时都在一个工程中。
可以看到单体应用缺点
部署成本高:无论是修改一行代码还是十行还是全部,所有的代码都需要替换。
改动影响大,风险高(耦合度高):在同一个工程里,你改动的内容可能有很多地方需要修改。
因为成本高,风险高,所以导致部署频率低(无法快速交付客户需求)

所以微服务的目的就是解决这些问题
怎么做呢?就是将系统应由原来的单体变成几十到几百个不同的工程。
这就是所谓的解耦,让每个服务可以独立运行。每一个子工程都会部署在一台服务器上,这么多服务器我们便称之为服务集群。

因此我们就可以看到微服务的优点
针对特定服务发布,影响小,风险小,成本低(因为服务分离了,增加服务只需加一个,对其它的不用全部更新)
频繁发布版本,快速交付需求
低成本扩容,弹性伸缩,适应云环境

当然,它也带来了很多缺点
分布式系统的复杂性
部署,测试和监控的成本问题
分布式事务和CAP的相关问题

产生服务间的依赖,服务如何拆封,内部接口规范,数据传递等问题,尤其是服务拆分,需要团队熟悉业务流程,懂得取舍,要保证拆分的粒度服务既符合“高内聚,低耦合”的基本原则,还要兼顾业务的发展以及公司的愿景,要还要说服团队成员为之努力,并且积极投入,在多方中间取得平衡。

二、踏出微服务(Spring Cloud)的第一步

既然都说了手摸手,那当然就是从创建工程开始,并且本次为了介绍微服务,所以会抛开dao层。使大家更清晰明了看到微服务的运转。首先肯定要自己装maven。

1、创建父工程

Create new project - maven - 勾选create from archetype - (maven-archetype-quickstart)-next
在这里插入图片描述
groupId 我这边就是org(个人)antry(我的网名)大家也可以和我一样,也可以用自己的。当然后面有的地方可能用到。注意一下就行,还有artifactId 是父工程名,我这边创建的父工程名时studycloud
在这里插入图片描述
选择自己的maven库
在这里插入图片描述
这就是文件存储位置
在这里插入图片描述

2、创建消费服务(custom-service)和user服务(user-service)

父工程创建好后我们先不急着配置,再创建两个子工程。
custom-service大家看这个名称可以理解这是一个消费者,因此这个user±service就是认为是生产者服务。再明了一点讲,我们一会儿就是要去访问custom的服务器,通过custom访问user服务。
在这里插入图片描述
后面其它选的和父工程是一样的,只有最后一步注意一下。
这个横杆需要自己加上,到这边它会没掉。
在这里插入图片描述
在这里插入图片描述
在每个子工程下创建resources文件夹
在这里插入图片描述
在这里插入图片描述

3、现在我们开始配置,配置成Spring Boot项目

当然了,学这个spring cloud 你要先去了解一下spring boot 了
下面话不多说,开始配置

3.1 父工程pom

添加 spring-boot parent标签

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.4.RELEASE</version>
  </parent>

3.2 子工程pom

两个子工程一样
首先告诉系统子工程的父亲,因此添加parent标签

  <parent>
    <groupId>org.antry</groupId>
    <artifactId>studycloud</artifactId>
    <version>1.0</version>
  </parent>

添加两个dependency

<!--    springboot 启动-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--    热启动依赖-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
    </dependency>

和一个plugin

 	   <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
       </plugin>

3.3 custom-service启动类

现在我们先测试custom工程是否能够使用,那么我这边也介绍一个插件,大家可以安装一下,用于快速创建启动类。
在这里插入图片描述
我们需要配置,所以我们也勾选这个application.yml,它会在resources下生成
在这里插入图片描述
大家记得刷新maven,不然会找不到包。

3.4 custom-service配置文件

application.yml中我们先配置端口和服务名

server:
  port: 9001
spring:
  application:
    name: custom-service

3.5 custom-service的service和control层

在这里插入图片描述
UserService接口

package org.antry.service;
/**
 * @ClassName UserService
 * @Description 接口
 * @Autor TT
 * @Date 2020/11/11 11:30
 * @Version 1.0
 */
public interface UserService {
    
    
    /**
     * 返回
     * @param id
     * @return
     */
    public String doGetUser(Long id);
}

UserServiceImpl实现类

package org.antry.service;
import org.springframework.stereotype.Service;
/**
 * @ClassName UserService
 * @Description 实现类
 * @Autor T_Antry
 * @Date 2020/11/11 11:26
 * @Version 1.0
 */
@Service
public class UserServiceImpl implements UserService{
    
    
   @Override
      public String doGetUser(Long id){
    
    
       return "custom-Service回应:" +
               "<div><h1>T_Antry工作室-springcloud动手了解</h1></div>" +
               "customService[无中转]:"+String.valueOf(id);
   }
}

handler类

package org.antry.controller;
import org.antry.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @ClassName UserHandler
 * @Description TODO
 * @Autor T_Antry
 * @Date 2020/11/11 11:32
 * @Version 1.0
 */
@RestController
@RequestMapping("user")
public class UserHandler {
    
    
    @Autowired
    private UserService userService;
    @GetMapping("/{id}")
    public String doGet(@PathVariable Long id){
    
    
        return userService.doGetUser(id);
    }
}

我们可以跑起来测试一下这个custom工程,现在还不是微服务,只是一个普通的spring boot 的工程。
运行起来之后,我们在url中输入 http://localhost:9001/user/123
我们就能够看到:

在这里插入图片描述

接下里,我们配置同样的步骤,也让user-service的工程也能够这样访问。当然,端口配置不同的端口,例如我这边就把它配置成1001,如下:

server:
  port: 1001
spring:
  application:
    name: user-service

测试结果如下:
在这里插入图片描述

3.6 开始入手微服务

我们现在呢就是做到去访问custom-service服务器去访问user-service
那么我们是通过Restemplate去访问的,一开始我看到RestTemplate是非常懵逼的,这其实就是一个类,也不是什么东西,现在还不必太过纠结这是什么东西。只需要知道,我们用这个类的对象来拿到其它服务器的执行结果就可以了。
这次测试我们不需要修改user-service的工程,我们只需要修改custom-service的handler,以及启动类。
启动类新增Template配置

package org.antry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class CustomService {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(CustomService.class, args);
    }
    @Bean
    public RestTemplate restTemplate(){
    
    
        return new RestTemplate();
    }
}

修改handler类
这个控制层,我们原本调用的是custom-service这台服务器自己本身的服务,那么我们现在通过写死的url去访问user-service,并拿到结果再返回。

package org.antry.controller;
import org.antry.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
 * @ClassName UserHandler
 * @Description TODO
 * @Autor T_Antry
 * @Date 2020/11/11 11:32
 * @Version 1.0
 */
@RestController
@RequestMapping("user")
public class UserHandler {
    
    
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private UserService userService;
    @GetMapping("/{id}")
    public String doGet(@PathVariable Long id){
    
    
       String url = "http://127.0.0.1:1001/user/"+id;
       return "<div><h1>custom-Service回应:</h1><div>"+restTemplate.getForObject(url, String.class);
      //  return userService.doGetUser(id);
    }
}

此时大家通过custom-service,就可以访问到user-service
在这里插入图片描述
以上的部分呢,其实我们已经可以看到服务之间可以通过这样的方式去联系,我想大家通过实践也能有自己的一些理解。
那么我也会把这一部分的源码上传,现在的这种方式当然大家也会认为它的不便捷,还要写死url等问题,我将会在下一章进行解释,喜欢就点个赞吧。
本次例程资源

猜你喜欢

转载自blog.csdn.net/qq_39150049/article/details/109597104