SpringCloud基础知识【概述、服务治理】

写在前面

微服务架构

  • "微服务" 一词源于Martin Fowler的名为Microservices的博文,可以在他的官方博客上找到:http://martinfowler.com/articles/microservices.html
  • 微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过HTTP的 RESTfuLAPI进行通信协作。
  • 被拆分成的每一个小型服务都围绕着系统中的某一项或些耦合度较高的业务功能进行构建,并且每个服务都维护着白身的数据存储、业务开发自动化测试案例以及独立部署机制。
  • 由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。

在这里插入图片描述

1. SpringCloud概述

  • Spring Cloud是一系列框架的 有序集合。 SpringCloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来。
  • 通过Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂易部署易维护分布式系统开发工具包
  • 它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册配置中心消息总线负载均衡断路器数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。

在这里插入图片描述

1.1 Spring Cloud版本命名方式

  • Spring Cloud版本命名方式采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如:
    • 最早的Release版本: Angel,第二个Release版本: Brixton,然后是CamdenDalstonEdgwareFinchleyGreenwichHoxton

1.2 Spring Cloud与Spring Boot版本对应关系

  • 注意:笔记中的实验均采用Spring Cloud 3.14、Spring Boot 2.7.4进行实验

在这里插入图片描述

2. SpringCloud 服务治理

2.1 Eureka 快速入门

  • Eureka是 Netflix公司开源的一个服务注册与发现的组件。
  • Eureka和其他Netflix公司的服务组件(例负载均衡、熔断器、网关等)一起,被Spring Cloud社区整合为Spring-Cloud-Netflix模块
  • Eureka包含两个组件: Eureka Server (注册中心)Eureka Client(服务提供者、服务消费者)。

在这里插入图片描述

2.1.1 框架搭建思路

  1. 搭建Provider和Consumer服务。
  2. 使用RestTemplate完成远程调用。
  3. 搭建Eureka Server 服务。
  4. 改造 Provider和Consumer称为 Eureka Client。
  5. Consumer 服务通过从Eureka Server中抓取Provider地址完成远程调用

在这里插入图片描述

2.1.2 搭建Provider和Consumer服务

  1. 首先,创建一个空的工程(spring-cloud),在工程中使用spring boot创建一个父模块(spring-clould-parent)。然后创建两个为web项目的spring boot模块作为服务提供者(eureka-provider)和服务消费者(eureka-consumer)

这里需要区分服务提供者(eureka-provider)和服务消费者(eureka-consumer)是在工程中创建的,还是在父模块(spring-clould-parent)中创建的。 我实在工程中创建的。和父模块同级,所以到最后使用父模块时,需要一些改动。
在这里插入图片描述

  1. 父模块
    • 父模块结构和pom.xml文件代码

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<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.itheima</groupId>
    <artifactId>spring-cloud-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--
    	如果从父模块和服务提供方和消费方模块同级,在引入下面两个模块时,记得加上packaging为pom,
    	不然报错:
   	 		packaging‘ with value ‘jar‘ is invalid. Aggregator projects require ‘pom‘ as packaging. 
   	 -->
    <packaging>pom</packaging> 

    <modules>
        <module>../eureka-provider</module>
        <module>../eureka-consumer</module>
    </modules>

    <!--spring boot 环境-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
</project>
  1. 服务提供者(eureka-provider)
    • 服务提供者结构和pom.xml、application.yml核心配置

在这里插入图片描述

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
server:
  port: 8000
  • 服务提供者(eureka-provider)
    • domain实体类
package com.itheima.eurekaprovider.domain;

public class Goods {
    private int id;
    private String title;
    private double price;
    private int count;

    public Goods() {
    }

    public Goods(int id, String title, double price, int count) {
        this.id = id;
        this.title = title;
        this.price = price;
        this.count = count;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

  • 服务提供者(eureka-provider)
    • dao层代码
package com.itheima.eurekaprovider.dao;

import com.itheima.eurekaprovider.domain.Goods;
import org.springframework.stereotype.Repository;

@Repository
public class Goodsdao {
    public Goods findOne(int id){
        return new Goods(1,"华为手机",3999,10000);
    }
}

  • 服务提供者(eureka-provider)
    • service层代码
package com.itheima.eurekaprovider.service;

import com.itheima.eurekaprovider.dao.Goodsdao;
import com.itheima.eurekaprovider.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class GoodsService {
    @Autowired
    private Goodsdao goodsdao;

    public Goods findOne(int id){
        return goodsdao.findOne(id);
    }
}

  • 服务提供者(eureka-provider)
    • controller层代码
package com.itheima.eurekaprovider.controller;

import com.itheima.eurekaprovider.domain.Goods;
import com.itheima.eurekaprovider.service.GoodsService;
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;

/**
 * 服务的提供方
 */

@RestController
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    private GoodsService goodsService;

    @GetMapping("/findOne/{id}")
    public Goods findOne(@PathVariable("id") int id){
       Goods goods = goodsService.findOne(id);
       return goods;
    }
}

  • 运行服务的提供方的启动类进行测试

在这里插入图片描述

  1. 服务消费者(eureka-consumer)
    • 服务消费者结构和pom.xml、application.yml核心配置

在这里插入图片描述

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
server:
  port: 9000
  • 服务消费者(eureka-consumer)
    • domain实体类与服务提供方一致,这里不再赘述
    • controller中的OrderController类用来调用服务提供者的服务
package com.itheima.eurekaconsumer.controller;
import com.itheima.eurekaconsumer.domain.Goods;

/**
 * 服务的调用方
 */

@RestController
@RequestMapping("order")
public class OrderController {

    @GetMapping("/goods/{id}")
    public Goods findGoodsById(@PathVariable("id") int id){
        System.out.println("findGoodsById...."+id);
        return null;
    }
}

  • 运行服务的消费方的启动类进行测试

在这里插入图片描述

控制台打印:findGoodsById…1

2.1.3 使用RestTemplate完成远程调用

  • Spring提供的一种简单便捷的模板类,用于在java代码里访问restful服务。
  • 功能与HttpClient类似,但是RestTemplate实现更优雅,使用更方便

书写消费方config包中restTemplate配置类

package com.itheima.eurekaconsumer.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

修改消费方OrderController类代码

package com.itheima.eurekaconsumer.controller;
import com.itheima.eurekaconsumer.domain.Goods;


/**
 * 服务的调用方
 */

@RestController
@RequestMapping("order")
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/goods/{id}")
    public Goods findGoodsById(@PathVariable("id") int id){
        System.out.println("findGoodsById...."+id);
        /*
            //远程调用Goods服务中的findOne接口
            使用 RestTemplate
            1.定义:Bean restTemplate
            2.注入: Bean
            3.调用方法
         */

        String url = "http://localhost:8000/goods/findOne/"+id;
        //调用方法
        Goods goods = restTemplate.getForObject(url,Goods.class);

        return goods;
    }
}

执行服务提供者和消费者的启动类

在这里插入图片描述

2.1.4 搭建Eureka Server 服务

1.在spring-cloud-parent模块中引入spring cloud依赖,修改spring-cloud-parent的pom.xml文件

	<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
       
        <!--spring-cloud 版本-->
        <spring-cloud.version>2021.0.4</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>

2.创建一个web工程的springboot模块(eureka-server),在pom.xml文件中引入下面信息,并修改启动类

  • eureka-server模块
    • pom.xml
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>3.1.4</version>
        </dependency>

    </dependencies>
  • eureka-server模块
    • 启动类
package com.itheima.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer   //添加该注解
@SpringBootApplication
public class EurekaServerApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaServerApplication.class, args);
    }

}

  • eureka-server模块
    • application.yml文件
server:
  port: 8761
# eureka配置
# 1. dashboard:eureka的web控制台信息
# 2. server: eureka的服务端配置
# 3. client: eureka的客户端配置
# 4. instance:eureka的实例配置
eureka:
  instance:
    hostname: localhost  # 主机名

  client:
    service-url: # eureka的服务端地址,将来客户端使用该地址和eureka通信
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

    register-with-eureka: false # 默认true, 是否将自己的路径注册到eureka上,eureka server不需要 eureka  provider client需要
    fetch-registry: false # 是否从eureka 中抓取路径,默认true, eureka server不需要 eureka  consumer client需要

  • 启动测试类,访问eureka成功。

在这里插入图片描述

2.1.5 改造 Provider 和 Consumer

服务提供方引入eureka信息

  • eureka-provider服务提供方
    • 修改eureka-provider服务提供方pom.xml
<!--eureka client-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
     <version>3.1.4</version>
</dependency>
  • eureka-provider服务提供方
    • 修改启动类
package com.itheima.eurekaprovider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient  //添加该注解,在新版本中可以省略,但是不建议
@SpringBootApplication()
public class EurekaProviderApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaProviderApplication.class, args);
    }

}

  • eureka-provider服务提供方
    • 修改application.yml
server:
  port: 8000


eureka:
  instance:
    hostname: localhost
  client:
    service-url: # eureka服务端地址,将来客户端使用该地址和eureka进行通信
      defaultZone: http://localhost:8761/eureka  # 不能使用https,会报错
spring:
  application:
    name: eureka-provider # 设置当前应用的名称,将来会在eureka中application显示。将来需要该名称获取路径。
  • 启动server和provider启动类

在这里插入图片描述

服务消费方引入eureka信息

  • 同上,不再赘述

2.1.6 使用 Eureka Server 完成远程调用

修改服务消费者的启动类

package com.itheima.eurekaconsumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableDiscoveryClient  //激活 DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class EurekaConsumerApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaConsumerApplication.class, args);
    }

}

修改服务消费方的OrderController类

package com.itheima.eurekaconsumer.controller;

import com.itheima.eurekaconsumer.domain.Goods;
//import com.netflix.discovery.DiscoveryClient; 不是这一个包
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;  //是这个包
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;

import java.util.List;

/**
 * 服务的调用方
 */

@RestController
@RequestMapping("order")
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/goods/{id}")
    public Goods findGoodsById(@PathVariable("id") int id){
        System.out.println("findGoodsById...."+id);

        /*
            //远程调用Goods服务中的findOne接口
            使用 RestTemplate
            1.定义:Bean restTemplate
            2.注入: Bean
            3.调用方法

            //动态从Eureka Server中获取provider的ip和端口
            1.启动类中注入DiscoveryClient对象,激活
            2.调用方法
         */

        //演示DiscoveryClient使用
        List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER"); // 不区分大小写

        if(instances == null || instances.size() == 0){
            return null;
        }

        ServiceInstance instance = instances.get(0); //因为只有一个,这里我们就获取第一个
        String host = instance.getHost();
        int port = instance.getPort();

        System.out.println(host);
        System.out.println(port);

        //String url = "http://localhost:8000/goods/findOne/"+id;
        String url = "http://"+host+":"+port+"/goods/findOne/"+id;
        //调用方法
        Goods goods = restTemplate.getForObject(url,Goods.class);

        return goods;
    }
}

开启测试

在这里插入图片描述

2.2 Eureka相关配置及特性

eureka 一共有4部分配置

  1. server: eureka的服务端配置
  2. client: eureka的客户端配置
  3. instance: eureka的实例配置
  4. dashboard: eureka的web控制台配置

1. instance

eureka:
	instance:
	hostname: localhost #主机名
	
	# 是否将自己的ip注册到eureka中,默认false, 注册主机名
	prefer-ip-address: false # false:localhost, true:172.16.98.134
	
	# 设置当前实例ip
	ip-address: 127.0.0.1 # 设置之后,172.16.98.134--->变成127.0.0.1
	
	# 修改instance-id显示,即eureka的web服务中显示的id. localhost:eureka-consumer:9000-->127.0.0.1:eureka-consumer:9000
	instance-id: ${eureka.instance.ip-address}:{spring.application.name}:{server.port} # ip:应用名称:端口 
	
	lease-renewal-interval-in-seconds: 30 #每一次eureka client向eureka server 发送心跳的时间间隔
	
	lease-expiration-duration-in-seconds: 90 #如果90 秒内eureka server没有收到eureka client的心跳包,则剔除该服务

2. server

eureka:
	server:
	# 是否开启自我保护机制,默认true
	enable-self- preservation:
	# 清理间脂(单位毫秒,默认60*1000)
	eviction-interval-timer-in-ms:

2.3 Eureka高可用

在这里插入图片描述

高可用演示

1. 使用springboot快速搭建两个Eureka Servers

pom.xml添加相关依赖
在这里插入图片描述

  • 为了实现下面配置,修改主机的hosts文件
    • http://eureka-server1:8761/eureka
    • http:// eureka-server2:8762/eureka

在这里插入图片描述

2. 分别进行配置,相互注册

在这里插入图片描述
在这里插入图片描述

  • 运行启动类

在这里插入图片描述
在这里插入图片描述

  • 查看

在这里插入图片描述

3. Eureka Client分别注册到这两个Eureka Server中

在这里插入图片描述
在这里插入图片描述

  • 分别启动eureka-provider和eureka-consumer

在这里插入图片描述

2.4 Consul快速入门

2.5 Nacos 快速入门

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值