狂神說springcloud筆記1_p1-p13


參考博文:(5條消息) [狂神說Java]SpringCloud筆記_笶生的博客-CSDN博客

(5條消息) 狂神說SpringCloud學習筆記(附帶源碼和筆記)_學不死就往死里學-CSDN博客

 

1、SpringCloud入門概述

1.1 SpringCloud是什么

springcloud官網: https://spring.io/projects/spring-cloud#learn

 

 

 

 

 

 

 

 

 

1.3 Dubbo 和 SpringCloud技術選型

1、分布式+服務治理Dubbo

目前成熟的互聯網架構:應用服務化拆分+消息中間件

 

 

 

2、Dubbo 和 SpringCloud對比

可以看一下社區活躍度

https://github.com/dubbo

https://github.com/springcloud

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

1.4 SpringCloud能干什么

在這里插入圖片描述

1.5 SpringCloud在哪下

官網 : https://spring.io/projects/spring-cloud/
在這里插入圖片描述
在這里插入圖片描述

2、總體介紹

在這里插入圖片描述
在這里插入圖片描述

2.1SpringCloud版本選擇

在這里插入圖片描述

3、創建父工程

直接創建一個名為SpringCloud的Maven空項目即可

然后后面全部的項目都是父工程的一個子模塊,並且都是maven的空項目

建立一個數據庫:db01
在這里插入圖片描述

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.bupt</groupId>
    <artifactId>springcloudLast</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>springcloud-api</module>
        <module>springcloud-consumer-dept-80</module>
        <module>springcloud-eureka-7001</module>
        <module>springcloud-provider-dept-8001</module>
        <module>springcloud-provider-dept-8002</module>
        <module>springcloud-provider-dept-8003</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springCloud的依賴-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringBoot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--數據庫-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
            <!--SpringBoot 啟動器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!--日志測試~-->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>

 

 同理springbootdependency和springclouddependy管理了所有spring-cloud-xxx-xxx和spring-boot-xxx-xxx的版本

注意是注意springboot的版本和springcloud版本的對應關系。

 

 

 

pom.xml

<!--當前的Module自己需要的依賴,如果父依賴中已經配置了,這里就不用寫了-->
<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies> 

Dept.java

@Data
@NoArgsConstructor
@Accessors(chain = true)  //鏈式寫法
//所有的實體類務必實現序列化,通訊需求
public class Dept implements Serializable {//Dept,實體類 orm 類表關系映射
    private static final long serialVersionUID = 708560364349809174L;
    private Long deptno; //主鍵
    private String dname;

    //看下這個數據存在哪個數據庫的字段~ 微服務 ,一個服務對應一個數據庫
    //同一個信息可能存在不同的數據庫
    private String db_source;

    public Dept(String dname) {
        this.dname = dname;
    }
}

5、服務提供者:springcloud-provider-dept-8001

 

 

 

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">
<parent>
<artifactId>springcloudLast</artifactId>
<groupId>com.bupt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>springcloud-provider-dept-8001</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.bupt</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
</project>

DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bupt.mapper.DeptMapper">
    <insert id="addDept" parameterType="Dept">
        insert into dept(dname,db_source)
        values (#{dname},DATABASE());
    </insert>

    <select id="queryById" resultType="Dept" parameterType="Long">
        select * from dept where deptno = #{deptno};
    </select>

    <select id="queryall" resultType="Dept">
        select * from dept;
    </select>
</mapper>

DeptMapper

@Mapper
@Repository
public interface DeptMapper {
    //添加部門
    boolean addDept(Dept dept);

    //根據ID查詢部門
    Dept queryById(@Param("deptno") long id);

    //查詢全部部門
    List<Dept> queryall();
}

DeptService

public interface DeptService {
    boolean addDept(Dept dept);

    Dept queryById(long id);

    List<Dept> queryall();

}

DeptServiceImpl

@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Override
    public boolean addDept(Dept dept) {
        return deptMapper.addDept(dept);
    }

    @Override
    public Dept queryById(long id) {
        return deptMapper.queryById(id);
    }

    @Override
    public List<Dept> queryall() {
        return deptMapper.queryall();
    }
}

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- configuration核心配置文件 -->
<configuration>
    <settings>
        <!--開啟二級緩存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

application.yml

server:
  port: 8001

mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml
  type-aliases-package: com.bupt.pojo
  configuration-properties: classpath:mybatis/mybatis-config.xml

spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/db01?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
    username: root
    password: root
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/

DeptController

package com.bupt.Controller;

import com.bupt.DeptService.DeptServiceImpl;
import com.bupt.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

//提供Restfull服務!!
@RestController
public class DeptController {

    @Autowired
    private DeptServiceImpl deptService;

    @RequestMapping("/dept/add")

    public boolean addDept(@RequestBody Dept dept) {
        System.out.println(dept);
        return deptService.addDept(dept);
    }


    @GetMapping("/dept/get/{id}")
    public Dept getDept(@PathVariable("id") Long id) {
        Dept dept = deptService.queryById(id);
        if (dept == null) {
            throw new RuntimeException("Fail");
        }
        return dept;
    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll() {
        return deptService.queryall();
    }

}

DeptProvider_8001

package com.bupt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//@EnableEurekaClient
@SpringBootApplication

public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

最后啟動項目訪問Controller里面的接口測試即可,這個pojo類在別的項目里面,我們照樣可以拿到,這就是微服務的簡單拆分的一個小例子

6、服務消費者:springcloud-consumer-dept-80

在這里插入圖片描述

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">
    <parent>
        <artifactId>springcloudLast</artifactId>
        <groupId>com.bupt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-dept-80</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.bupt</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>

這里要用到 RestTemplate ,但是它的類中沒有Bean,所以我們要把它注冊到Bean中

ConfigBean

package com.bupt.config;

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

@Configuration
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

DeptConsumerController

package com.bupt.controller;

import com.bupt.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;

@Controller
public class DeptConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    private static final  String REST_URL_PREFIX = "http://localhost:8001";

    @RequestMapping("/consumer/dept/get/{id}")
    @ResponseBody
    public Dept getDept(@PathVariable("id") long id)
    {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id,Dept.class);
    }

    @RequestMapping("/consumer/dept/add")
    @ResponseBody
    public boolean add(Dept dept){

        HashMap<String, Object> map = new HashMap<>();
        map.put("dname",dept.getDname());
        map.put("deptNo",dept.getDeptno());
        map.put("db_source",dept.getDb_source());
        System.out.println(map);
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", map, Boolean.class);
    }

    @RequestMapping("/consumer/dept/list")
    @ResponseBody
    public List<Dept> queryAll(){
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list",List.class);
    }





}

然后你會發現,原來遠程的post請求直接在url是拒絕訪問的,但是在這個里面可以訪問,只是結果為null

application.yml

server: port: 80

主啟動類DeptConsumer_80

@SpringBootApplication
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class, args);
    }
}

最后啟動服務提供者 springcloud-provider-dept-8001

然后啟動服務消費者 springcloud-consumer-dept-80

通過服務消費者的url請求去獲取服務提供者對應的請求,照樣可以拿到

7、Eureka服務注冊與發現
7.1、什么是Eureka

 

 

7.2、原理講解

 

 

 

 

 

 

 

 

 

7.3、springcloud-eureka-7001

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">
    <parent>
        <artifactId>springcloudLast</artifactId>
        <groupId>com.bupt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-eureka-7001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 7001

# Eureka配置
eureka:
  instance:
    # Eureka服務端的實例名字
    hostname: 127.0.0.1
  client:
    # 表示是否向 Eureka 注冊中心注冊自己(這個模塊本身是服務器,所以不需要)
    register-with-eureka: false
    # fetch-registry如果為false,則表示自己為注冊中心,客戶端的化為 ture
    fetch-registry: false
    # Eureka監控頁面~
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

主啟動類:EurekaServer_7001

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer表示服務端的啟動類,可以接收別人注冊進來
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigEurekaServer_7001.class, args);
    }
}

啟動之后訪問 http://localhost:7001/
在這里插入圖片描述

Eureka的自我保護機制

在這里插入圖片描述

7.4、8001服務注冊與發現

springcloud-provider-dept-8001

首先肯定是要導入對應的依賴

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">
    <parent>
        <artifactId>springcloudLast</artifactId>
        <groupId>com.bupt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-dept-8001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.bupt</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
    </dependencies>
</project>

主要是spring-cloud-starter-eureka依賴,注意版本

然后在配置文件中添加對應的Eureka注冊配置

application.yml

server:
  port: 8001

mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml
  type-aliases-package: com.bupt.pojo
  configuration-properties: classpath:mybatis/mybatis-config.xml

spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/db01?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
    username: root
    password: root
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/

 

最后在主啟動類上添加注解

@EnableEurekaClient //在服務啟動后自動注冊到Eureka中
1
啟動springcloud-config-eureka-7001,啟動完畢后再啟動下面的服務

啟動springcloud-provider-dept-8001,等一會再次訪問 http://localhost:7001/

 

 

actuator完善監控信息

所以這個時候我們應該是少了什么東西,然后我們繼續在 8001 里面添加依賴

<!--actuator完善監控信息-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

重啟8001項目再次點擊服務狀態信息,跳到了一個頁面,但是里面什么都沒有,這個時候我們就要配置一些信息了,這個信息只是在團隊開發的時候別人會通過這個信息來了解這個服務是誰寫的

現在我們在8001項目的配置文件中添加一些配置

#eureka 的配置,服務注冊到哪里
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept8001  #修改Eureka上的默認的狀態名字

#info配置(點擊狀態信息會返回的東西,可以百度)
info:
  app.name: wulei-springcloud    
  company.name: blog.wulei2921625957.com

然后你重啟8001項目,再次點擊項目狀態信息會返回你在上面添加的信息

那如何通過代碼來讓別人發現自己呢?

服務發現

在8001項目的controller里面添加

import org.springframework.cloud.client.discovery.DiscoveryClient;

//獲取一些配置的信息,得到一些具體微服務
@Autowired
private DiscoveryClient client;

//注冊進來的微服務~ ,獲取一些信息
@GetMapping("/dept/discovery")
public Object discovery() {
    //獲取微服務列表的清單
    List<String> services = client.getServices();
    System.out.println("discovery=>services:" + services);

    //得到一個具體的微服務信息,通過具體的微服務ID applicationName
    List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
    for (ServiceInstance instance : instances) {
        System.out.println(
            instance.getHost() + "\t" +
            instance.getPort() + "\t" +
            instance.getUri() + "\t" +
            instance.getServiceId()
        );
    }
    return instances;
}

然后在8001項目主啟動類上添加服務發現注解即可

這個注解我試了一下,不加也可以訪問上面的接口返回信息

@EnableDiscoveryClient //服務發現 
  • 1

重啟8001項目並訪問 http://localhost:8001/dept/discovery

在這里插入圖片描述

 @EnableDiscoveryClient和@EnableEurekaClient的區別

 

 

 

 為啥在客戶端EnableEurekaClient可以省略不寫呢?

https://www.pianshen.com/article/22731105426/

server.servlet.context-path配置的作用和springboot2.0變革后的配置區別

 

 

 

 

8、Eureka集群的搭建


8.1、修改域名映射
為了體驗集群搭載在不同的電腦上,我們進入C:\Windows\System32\drivers\etc里面修改hosts文件,在文件的末尾添加下面幾行

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
8.2、修改7001配置文件
application.yml

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com #Eureka服務端的實例名字
  client:
    register-with-eureka: false #表示是否向 Eureka 注冊中心注冊自己(這個模塊本身是服務器,所以不需要)
    fetch-registry: false #fetch-registry如果為false,則表示自己為注冊中心
    service-url: #監控頁面~
      #重寫Eureka的默認端口以及訪問路徑 --->http://localhost:7001/eureka/
      # 單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(關聯):7001關聯7002、7003
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

8.3 、springcloud-eureka-7002

創建Eureka注冊中心7002項目(和7001一模一樣)

pom.xml

依賴和7001一樣

EurekaServer_7002

主啟動類

package com.bupt;

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

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer表示服務端的啟動類,可以接收別人注冊進來
public class EurekaServer_7002 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7002.class, args);
    }
}

application.yml

server:
  port: 7002

#Eureka配置
eureka:
  instance:
    hostname: eureka7002.com #Eureka服務端的實例名字
  client:
    register-with-eureka: false #表示是否向 Eureka 注冊中心注冊自己(這個模塊本身是服務器,所以不需要)
    fetch-registry: false #fetch-registry如果為false,則表示自己為注冊中心
    service-url: #監控頁面~
      #重寫Eureka的默認端口以及訪問路徑 --->http://localhost:7001/eureka/
      # 單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(關聯):7002關聯7001、7003
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/

8.4 、springcloud-eureka-7003

創建Eureka注冊中心7003項目(和7001一模一樣)

pom.xml

依賴和7001一樣

EurekaServer_7003

主啟動類

package com.bupt;

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

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer表示服務端的啟動類,可以接收別人注冊進來
public class EurekaServer_7003 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7003.class, args);
    }
}

application.yml

server:
  port: 7003

#Eureka配置
eureka:
  instance:
    hostname: eureka7003.com #Eureka服務端的實例名字
  client:
    register-with-eureka: false #表示是否向 Eureka 注冊中心注冊自己(這個模塊本身是服務器,所以不需要)
    fetch-registry: false #fetch-registry如果為false,則表示自己為注冊中心
    service-url: #監控頁面~
      #重寫Eureka的默認端口以及訪問路徑 --->http://localhost:7001/eureka/
      # 單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(關聯):7002關聯7001、7003
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

然后啟動7001、7002、7003項目

然后訪問:http://localhost:7001/ 、http://localhost:7002/ 、http://localhost:7003/

 

8.5、8001項目注冊多個注冊中心
要把8001項目注冊到多個注冊中心上去,其實很簡單,只需要改動配置文件即可

application.yml(8001)

server:
  port: 8001

mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml
  type-aliases-package: com.bupt.pojo
  configuration-properties: classpath:mybatis/mybatis-config.xml

spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/db01?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
    username: root
    password: root
# Eureka配置:配置服務注冊中心地址
eureka:
  client:
    service-url:
      # 注冊中心地址7001-7003
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept-8001 #修改Eureka上的默認描述信息

info:
  app.name: wulei-springcloud
  company.name: blog.wulei2921625957.com

然后啟動8001項目,刷新http://localhost:7001/ 、http://localhost:7002/ 、http://localhost:7003/ 即可發現

 

 

 

9、CAP原則及對比Zookeeper

在這里插入圖片描述

在這里插入圖片描述

作為服務注冊中心,Eureka比Zookeeper好在那里?

 

 

 

張大胖和CAP定理(分布式系統、可用性、一致性、分區容錯性)_ITPUB博客

 

在這里插入圖片描述
在這里插入圖片描述

10、Ribbon負載均衡

ribbon是什么?

在這里插入圖片描述

ribbon能干什么?

在這里插入圖片描述

10.1、springcloud-consumer-dept-80使用Ribbon

首先80項目要添加兩個依賴

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">
    <parent>
        <artifactId>springcloudLast</artifactId>
        <groupId>com.bupt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-fdept-feign</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.bupt</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!--Ribbon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--Eureka: Ribbon需要從Eureka服務中心獲取要拿什么-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--Feign的依賴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

    </dependencies>
</project>

由於我們消費者客戶端是利用RestTemplate來進行服務的讀取,所以我們讓RestTemplate實現負載均衡,只需要加一個注解即可@LoadBalanced

ConfigBean

 @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

 

由於我們導入了Eureka,所以我們要配置Eureka

application.yml

server:
  port: 80

# Eureka配置
eureka:
  client:
    register-with-eureka: false # 不向 Eureka注冊自己
    service-url: # 從三個注冊中心中隨機取一個去訪問
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#spring:
#  application:
#    name: SpringBoot_easyPOI
#  main:
#    allow-bean-definition-overriding: true

DeptConsumer_80

package com.bupt;

//import com.bupt.MyRule.MyRule;
import com.MyRule.MyRules;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = MyRules.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}
最后還有一個問題,就是我們的RestTemplate實現了負載均衡,那么怎么體現它呢?我們現在就只是在它身上加了一個注解,那肯定是不行的,我們還要改變RestTemplate的請求路徑,讓其自動選擇,而不是寫死
package com.MyRule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRules {

    @Bean
    public IRule testRule(){
        return new MyRandomRule();
    }

}

 

DeptConsumerController
//private static final String REST_URL_PREFIX = "http://localhost:8001";
//用Ribbon做負載均衡的時候不應該寫它,不應該寫死,地址應該是一個變量,通過服務名來訪問
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

package com.bupt.controller;

import com.bupt.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;

@Controller
public class DeptConsumerController {

    @Autowired
    private RestTemplate restTemplate;

//    private static final  String REST_URL_PREFIX = "http://localhost:8001";
//Ribbon:我們這里的地址,應該是一個變量,通過服務名來訪問
//private static final String REST_URL_PREFIX = "http://localhost:8001";
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

    @RequestMapping("/consumer/dept/get/{id}")
    @ResponseBody
    public Dept getDept(@PathVariable("id") long id)
    {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id,Dept.class);
    }

    @RequestMapping("/consumer/dept/add")
    @ResponseBody
    public boolean add(Dept dept){

        HashMap<String, Object> map = new HashMap<>();
        map.put("dname",dept.getDname());
        map.put("deptNo",dept.getDeptno());
        map.put("db_source",dept.getDb_source());
        System.out.println(map);
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", map, Boolean.class);
    }

    @RequestMapping("/consumer/dept/list")
    @ResponseBody
    public List<Dept> queryAll(){
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list",List.class);
    }





}

 

最后啟動7001、7002、7003項目后再啟動8001項目,等8001項目注冊到它們3個中后啟動80項目

然后訪問 http://localhost/consumer/dept/list 可以看到正常返回結果,當然了,在這里也看不出負載均衡,所以下面會配置多個服務提供者和多個數據庫,來測試負載均衡的效果。

10.2、使用Ribbon實現負載均衡

 

 


創建另外兩個數據庫:db02、db03

 

 

 

 

創建另外兩個服務提供者:8002、8003

直接新建兩個子model,然后把8001的所有文件全部拷貝(提供相同的服務),一摸一樣的,然后更改一下配置文件即可

pom.xml依賴

application.yml的端口號,對應的數據庫,還有instance-id,例如:instance-id: springcloud-provider-dept8002

注意:下面的這個服務ID不要改

spring:
  application:
    name: springcloud-provider-dept  # 3個服務名稱一致是前提

現在的項目預覽


然后,啟動

springcloud-config-eureka-7001
springcloud-config-eureka-7002
springcloud-config-eureka-7003
springcloud-provider-dept-8001
springcloud-provider-dept-8002
springcloud-provider-dept-8003
springcloud-consumer-dept-80

然后訪問http://localhost/consumer/dept/list ,多訪問幾次,查詢的數據沒變,但是數據庫變了

你會發現是輪詢,就是每個服務輪流來,這也Ribbon的默認算法

Ribbon自定義均衡算法
里面有個接口非常重要:IRule,基本上全部的均衡算法都實現了這個接口

里面有這么多均衡算法,因為默認是輪詢算法,也就是RoundRobinRule,那我們要怎么使用別的算法呢?

只需要在80項目的config類里面注冊Bean即可

//IRule
//RoundRobinRule:輪詢
//RandomRule:隨機
//AvailabilityFilteringRule:會先過濾掉跳閘、訪問故障的服務~,對剩下的進行輪詢
//RetryRule:會先按照輪詢獲取服務,如果服務獲取失敗,則會在指定的時間內進行重試
@Bean
public IRule myRule() {
    return new RandomRule(); //默認為輪詢,現在我們使用隨機的
}

然后啟動80項目,訪問http://localhost/consumer/dept/list,多訪問幾次,發現每次出現的數據庫都沒規律可循

我們要學會自定義負載均衡算法,為了體現我們使用了自定義的負載均衡算法,我們建包不建在主啟動類的同級目錄(官方建議)

 

 當兩個Irule在同一個文件夾下,此時會沖突報錯

 

 

 

 把剛剛寫在ConfigBean里面的Bean注釋掉(不能在掃描包下出現兩個Irule),我們來模仿它的算法寫一個自己的算法

自定義類MyRandomRule

package com.MyRule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancer;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;


public class MyRandomRule extends AbstractLoadBalancerRule {

    //每個機器,訪問5次,換下一個服務(總共3個)
    //total = 0 默認=0,如果=5,我們指向下一個服務結點
    //index = 0 默認=0,如果total=5,那么index+1,

    private int total = 0; //被調用的次數
    private int currentIndex = 0; //當前是誰在提供服務

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers(); //獲得還活着的服務
            List<Server> allList = lb.getAllServers();  //獲得全部的服務

            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

            //=============================================================

            if (total < 5) {
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex >= serverCount) {
                    currentIndex = 0;
                }
            }
            server = upList.get(currentIndex);
            //=============================================================
            if (server == null) {
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }
            server = null;
            Thread.yield();
        }

        return server;

    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {

    }
}

MyRules

package com.MyRule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRules {

    @Bean
    public IRule testRule(){
        return new MyRandomRule();
    }

}

最后還要在主啟動類添加掃描注解,在微服務啟動的時候就能去加載我們自定義的Ribbon類

DeptConsumer_80

package com.bupt;

//import com.bupt.MyRule.MyRule;
import com.MyRule.MyRules;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = MyRules.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

然后重啟80項目,訪問http://localhost/consumer/dept/list,多訪問幾次,可以發現訪問的服務每5次切換一下

11、Feign負載均衡

11.1、簡介

在這里插入圖片描述

11.2、Feign能干什么?

在這里插入圖片描述

11.3、Feign集成了Ribbon

在這里插入圖片描述

11.4 springcloud-consumer-dept-feign

在這里插入圖片描述

創建一個springcloud-consumer-dept-feign空maven的空項目,這也是一個消費者,端口也是80,只是這個消費者使用Feign實現的負載均衡

在這里插入圖片描述

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">
    <parent>
        <artifactId>springcloudLast</artifactId>
        <groupId>com.bupt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-fdept-feign</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.bupt</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!--Ribbon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--Eureka: Ribbon需要從Eureka服務中心獲取要拿什么-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--Feign的依賴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

    </dependencies>
</project>

application.yml

和springcloud-consumer-dept-80項目的一摸一樣

server:
  port: 80

# Eureka配置
eureka:
  client:
    register-with-eureka: false # 不向 Eureka注冊自己
    service-url: # 從三個注冊中心中隨機取一個去訪問
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#spring:
#  application:
#    name: SpringBoot_easyPOI
#  main:
#    allow-bean-definition-overriding: true

修改springcloud-api

  • 添加依賴

 

 

  • 並寫上幾個注解

  • feign注解實現的服務請求接口是和provider的controller請求路由保持一致,但是沒有方法體
package com.bupt.service;

import com.bupt.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")  //在接口上添加注解就可以實現相關服務的負載均衡
public interface DeptClientService {

    @RequestMapping("/dept/add")
    public boolean addDept(@RequestBody Dept dept) ;


    @GetMapping("/dept/get/{id}")
    public Dept getDept(@PathVariable("id") Long id) ;

    @GetMapping("/dept/list")
    public List<Dept> queryAll() ;
}

然后在springcloud-consumer-dept-feign項目的controller也要做相應的修改

DeptConsumerController

package com.bupt.controller;

import com.bupt.pojo.Dept;
import com.bupt.service.DeptClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class DeptConsumerController {

    @Autowired
    private DeptClientService deptClientService = null;

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept queryById(@PathVariable("id") long id){
        return this.deptClientService.getDept(id);
    }

    @RequestMapping("/consumer/dept/add")
    public boolean add(@RequestBody Dept dept){
        return this.deptClientService.addDept(dept);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> queryAll(){
        return this.deptClientService.queryAll();
    }

}

最后還要在啟動類上添加FeignClient注解

FeignDeptConsumer_80

package com.bupt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;

@SpringBootApplication
@EnableFeignClients(basePackages = {"com.bupt"})
public class FeignDeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignDeptConsumer_80.class,args);
    }

}

最后啟動7001、… 、8001、… 、feign的80項目,測試

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM