Java架构微服务入门篇

SPRINGCLOUD学习篇

一、SPRINGCLOUD整合Eureka

创建一个父工程

项目名称:cloud2020
在这里插入图片描述
编写POM文件

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.cloud</groupId>
  <artifactId>cloud2020</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!--    统一管理jar包版本-->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.coompiler.targer>1.8</maven.coompiler.targer>
    <junit.version>4.12</junit.version>
    <log4j.version>1.2.17</log4j.version>
    <lombok.version>1.16.18</lombok.version>
    <mysql.version>5.1.47</mysql.version>
    <druid.version>1.1.16</druid.version>
    <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
  </properties>
  <!--    dependencyManagement 子模块继承后,提供作用:锁定版本+子module不用写groupID和version-->
  <dependencyManagement>
    <dependencies>
      <!-- springboot 2.2.2-->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.2.2.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--            spring cloud Hoxton.sR1-->
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--            spring cloud alibaba 2.1.0.RELEASE-->
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.1.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--            mysql connector-->
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
      </dependency>
      <!--            druid 数据连接池-->
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
      </dependency>
      <!--            mybatis框架-->
      <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>${mybatis.spring.boot.version}</version>
      </dependency>
      <!--            juint-->
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
      </dependency>
      <!--            log4j-->
      <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
        <!--            lombokjar包依赖-->
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <optional>true</optional>
      </dependency>

    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <fork>true</fork>
          <addResources>true</addResources>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
  1. Maven使用dependencyManagement元素来提供了一种管理依赖版本号的方式。
  2. 通常会在一个组织或者项目的最顶层的父pom中可以看到dependencyManagement元素。
  3. 使用pom.xml中的dependencyManagement元素能让所有在子项目中引用一个依赖而不用显示的列出版本号。
  4. Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后他就会使用这个dependencyManagement元素中指定的版本号。
  5. dependencyManagement 对jar版本统一管理 ,只做声明,并不会引入。

总结:这样做的好处就是:如果有多个子项目都引用用一个依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个项目的修改;另外如果某个子项目需要另外的一个版本,只需要声明version即可。
dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。
如果不存在子项目中声明依赖,是不会从父项目中继承下来的,只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom
如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

跳过单元测试

设置跳过测试类
在这里插入图片描述

二、cloud-provider-payment8001

1、创建一个消费者来消费消息
2、创建一个生产者来生产消息
如图所示:
在这里插入图片描述

项目名称:cloud-provider-payment8001

1、创建项目

创建微服务提供者支付Module模块
第一步:
在这里插入图片描述第二步:
在这里插入图片描述
第三步:
在这里插入图片描述

2、 修改POM文件

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.23</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3、修改YML文件

#服务端口
server:
  port: 8001
#服务名称
spring:
  application:
    name: cloud-payment-service
#数据源的配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
#配置mybatis
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.cloud.springcloud.entity

4、创建主启动类

package com.cloud.springcloud;

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

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

5、业务逻辑开发

1、创建数据库

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for payment
-- ----------------------------
DROP TABLE IF EXISTS `payment`;
CREATE TABLE `payment` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `serial` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of payment
-- ----------------------------
BEGIN;
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

2、创建实体对象
类名称为:Payment

package com.cloud.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
    private  Long id;
    private  String serial;
}

封装一个结果对象
类名称为:commonResult

package com.cloud.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResult <T>{
    private  Integer code;
    private  String  message;
    private  T  data;

    public CommonResult(Integer code,String message){

        this(code,message,null);
    }
}

3 、编写dao接口
接口名称为:PaymentDao

 package com.cloud.springcloud.dao;

import com.cloud.springcloud.entity.Payment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface PaymentDao {
    public  int create(Payment payment);
    public  Payment getPaymentById(@Param("id") Long id);
}

4、编写映射文件
在resource目录下新建一个mapper文件夹
在mapper文件夹中新建一个PaymentMapper.xml文件
在PaymentMapper.xml文件中编写新增,查询sql语句
编写:PaymentMapper.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.cloud.springcloud.dao.PaymentDao">
<!--新增语句-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial) values(#{serial});
    </insert>
<!--结果集映射处理-->
    <resultMap id="BaseResultMap" type="com.cloud.springcloud.entity.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
<!--查询语句-->
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap" >
        select * from payment where id=#{id};
    </select>
</mapper>

5、编写业务逻辑层
1、编写service接口
创建一个PaymentService接口类

package com.cloud.springcloud.service;

import com.cloud.springcloud.entity.Payment;

public interface PaymentService {
    public  int create(Payment payment);
    public  Payment getPaymentById(Long id);
}

2、编写service实现类
创建一个PaymentServiceImpl类

package com.cloud.springcloud.service.impl;

import com.cloud.springcloud.dao.PaymentDao;
import com.cloud.springcloud.entity.Payment;
import com.cloud.springcloud.service.PaymentService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
@Service
public class PaymentServiceImpl implements PaymentService {
    @Resource
    private PaymentDao paymentDao;

    @Override
    public int create(Payment payment) {
        return paymentDao.create(payment);
    }

    @Override
    public Payment getPaymentById(Long id) {
        return paymentDao.getPaymentById(id);
    }
}

6、编写控制层Controller
创建一个PaymentController类

package com.cloud.springcloud.controller;

import com.cloud.springcloud.entity.CommonResult;
import com.cloud.springcloud.entity.Payment;
import com.cloud.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;
    @PostMapping(value = "/payment/create")
    public CommonResult create(Payment payment){
        int result=paymentService.create(payment);
        log.info("*****插入结果"+result);
        if(result>0){
            return  new CommonResult(200,"插入数据库成功",result);
        }else {
            return  new CommonResult(201,"插入数据库失败",null);
        }
    }

    @GetMapping(value="/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        Payment payment=paymentService.getPaymentById(id);
        log.info("*****查询结果:"+payment);
        if(payment!=null){
            return  new CommonResult(200,"查询成功!",payment);
        }else {
            return  new CommonResult(201,"没有找到对应记录,查询ID!"+id,null);
        }
    }
}

7、测试结果
查询结果:
测试地址:http://localhost:8001/payment/get/1
在这里插入图片描述
新增结果:
测试地址为:http://localhost:8001/payment/create
在这里插入图片描述

6、开启热部署项目

1、在pom.xml文件中添加依赖
在这里插入图片描述

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

添加maven插件

在父工程中添加maven插件
在这里插入图片描述

<build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <fork>true</fork>
          <addResources>true</addResources>
        </configuration>
      </plugin>
    </plugins>
  </build>

设置开启自动编译:
在这里插入图片描述
更新修改的值:
在这里插入图片描述
修改以下两个值:
在这里插入图片描述
最后重启以下IDEA

三、cloud-consumer-order80

1、创建项目

项目名称:cloud-consumer-order80

微服务消费者订单Module模块
第一步:创建订单项目 cloud-consumer-order80
在这里插入图片描述

2、修改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-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3、编写YML文件

在resource文件下建一个application.yml文件
编写配置,内容如下:

#编写项目端口号
server:
  port: 80
spring:
  application:
    name: cloud-order-service 

4、编写主启动类

package com.cloud.springcloud;

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

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

5、编写实体类

类名为:Payment

package com.cloud.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;


@NoArgsConstructor
@AllArgsConstructor
@Data
public class Payment implements Serializable {
    private  Long id;
    private  String serial;
}

类名称为:commonResult

package com.cloud.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
    private  Integer code;
    private  String  message;
    private  T  data;

    public CommonResult(Integer code,String message){

        this(code,message,null);
    }
}

6、编写控制层

package com.cloud.springcloud.controller;

import com.cloud.springcloud.entity.CommonResult;
import com.cloud.springcloud.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderController {
    public static final String PAYMENT_URL="http://localhost:8001";
    @Resource
    private RestTemplate restTemplate;
    @PostMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment){
        log.info("*****新增记录:"+payment);
        return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
    }

    @GetMapping("consumer/payment/get/{id}")
    public  CommonResult<Payment> getPayment(@PathVariable("id")Long id){
        log.info("*****查询记录:"+id);
        return  restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
    }
}

7、编写一个配置类

类名为:ApplicationContextConfig

package com.cloud.springcloud.config;

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

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

8、测试结果:

测试查询地址:http://localhost/consumer/payment/get/1
在这里插入图片描述
测试新增地址:http://localhost/consumer/payment/create?serial=aaaddcaac
在这里插入图片描述

如果出现值插入为null,修改cloud-provider-payment80中控制层新增接口,添加一个@RequestBody 如图所示:
在这里插入图片描述

三、cloud-api-commons

1、创建项目

第一步:
在这里插入图片描述
第二步:
在这里插入图片描述

2、修改pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
</dependencies>

3、进行项目打包

cloud-api-commons 打包给其他两项目进行使用
打包方式如图所示:
在这里插入图片描述

4、删除项目中实体对象

cloud-provider-payment8001
cloud-consumer-order80
具体操作,如图所示:

cloud-provider-payment8001
在这里插入图片描述
cloud-consumer-order80
在这里插入图片描述

实体类删除后两项目都报错。
需要给两个项目进行添加依赖
具体操作如下:

cloud-provider-payment8001
cloud-consumer-order80

<dependency>
     <groupId>com.cloud</groupId>
     <artifactId>cloud-api-commons</artifactId>
     <version>1.0-SNAPSHOT</version>
</dependency>

5、测试项目

查询结果:
查询地址:http://localhost/consumer/payment/get/1在这里插入图片描述
新增地址:http://localhost/consumer/payment/create?serial=aaad3333
在这里插入图片描述

整体架构

架构设计图

整体架构图如下:
在这里插入图片描述

四、Eureka 服务注册与发现

Eureka 服务的治理
Eureka 采用了CS架构模型,Eureka Server做为服务的注册功能的服务器,它是注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接,这样系统的维护人员就可以通过Eureka Server 来监控系统中各个微服是否正常运行。
在服务注册与发现中,有一个注册中心,当服务器启动的时候,会把当前自己服务的信息 比如(服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址)
在这里插入图片描述
Eureka包含两个组件:
Eureka Server提供服务注册服务
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中可以直观的看到。
Eureka Client通过注册中心进行访问
是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的,使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server 在多个心跳周期内没有接收到某个节点心跳 Eureka Server 将会从服务注册列表中把这个服务节点移除(默认90秒)

单机版本Eureka架构

1、创建项目 cloud-eureka-server7001

创建项目如图所示:这里是引用

2、修改POM.xml文件

 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.cloud</groupId>
            <artifactId>cloud-api-commons</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-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

3、编写YML配置文件

创建在resource下创建一个application.yml文件

#编写服务端口
server:
  port: 7001
#编写服务名称
eureka:
  instance:
    hostname: localhost #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

4、编写主启动类

类名称为:EurekaMain7001

package com.cloud.springcloud;

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

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

5、测试结果

测试地址:http://localhost:7001/
在这里插入图片描述

6、修改服务(8001/80项目)

修改以下服务:
cloud-provider-payment8001项目
cloud-consumer-order80项目
具体修改如下:
第一步:
在cloud-provider-payment8001 的pom中添加依赖

cloud-provider-payment8001

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

第二步:
在cloud-provider-payment8001 的application.yml文件修改

#Eureka 客户端配置
eureka:
  client:
    #表示是否将自己注册进Eureka Server中去,默认是true。
    register-with-eureka: true
    #是否从Eureka Server 抓取已有的注册信息,
    #默认为:true 但节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

第三步:
在cloud-provider-payment8001 的主启动类添加注解
在这里插入图片描述
第四步:
进行项目启动测试:
在这里插入图片描述

cloud-consumer-order80

第一步:
给cloud-consumer-order80 的pom文件中添加依赖

 <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>

第二步:
修改cloud-consumer-order80 中application.yml文件

#Eureka配置
eureka:
  client:
    #表示是否将自己注册进Eureka Server中 默认为true
    register-with-eureka: true
    #是否从Eureka Server抓取已有注册信息,默认为true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

第三步:
修改cloud-consumer-order80 中的主启动类添加注解
如图所示:
在这里插入图片描述
第四步:
重启项目查看是否注册成功!
查看地址:http://localhost:7001/
在这里插入图片描述

五、Eureka集群搭建

解决单点故障,实现高可用
解决方案:搭建Eureka注册中心集群,实现负载均衡+ 故障容错。
参考项目cloud-eureka-server7001
创建项目cloud-eureka-server7002

1、cloud-eureka-server7002

在这里插入图片描述

2、修改POM.xml

可以直接拷贝cloud-eureka-server7001中pom依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.cloud</groupId>
            <artifactId>cloud-api-commons</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-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

3、编写YML文件

在resource文件下 新建一个application.yml
并添加如下内容:
由于localhost多个项目会出现重名的现象所以需要做映射处理
修改host文件
mac系统 sudo vim /etc/hosts
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
第一步:先修改7001中的yml文件
内容如下:

#编写服务端口
server:
  port: 7001
#编写服务名称
eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7002.com:7002/eureka/

第二步编写7002 application.yml文件

#编写服务端口
server:
  port: 7002
#编写服务名称
eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka/

4、编写主启动类

package com.cloud.springcloud;

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

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

5、测试结果

查看是否有互相注册
如图所示:7001中有7002在这里插入图片描述
7002中有7001
在这里插入图片描述

六、配置8001与80项目注册到Eureka集群中

1、具体配置

第一步:修改cloud-provider-payment8001 中application.xml文件
内容如下:
修改defaultZone的值

#Eureka 客户端配置
eureka:
  client:
    #表示是否将自己注册进Eureka Server中去,默认是true。
    register-with-eureka: true
    #是否从Eureka Server 抓取已有的注册信息,默认为:true 但节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版本

第二步:修改cloud-consumer-order80 中application.yml文件
内容如下:
修改位置:defaultZone的值


#Eureka配置
eureka:
  client:
    #表示是否将自己注册进Eureka Server中 默认为true
    register-with-eureka: true
    #是否从Eureka Server抓取已有注册信息,默认为true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

2、测试结果

重启项目:
7002服务
结果如图所示:在这里插入图片描述
测试结果7001
如图所示:
在这里插入图片描述

七、搭建提供者集群

参考:cloud-provider-payment8001
创建:cloud-provider-payment8002
如图所示:

1、创建项目: cloud-provider-payment8002

在这里插入图片描述

2、修改pom文件

可以直接拷贝cloud-provider-payment8001 pom依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.23</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
</dependencies>

3、编写YAML文件

在resource文件下新建一个application.yml 文件
可以直接复制cloud-provider-payment8001 中的application.yml文件内容
1、修改端口号
修改Spring.application.name值
如图所示:

#服务端口
server:
  port: 8002
#服务名称
spring:
  application:
    name: cloud-payment-service
#数据源的配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
#配置mybatis
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.cloud.springcloud.entity


#Eureka 客户端配置
eureka:
  client:
    #表示是否将自己注册进Eureka Server中去,默认是true。
    register-with-eureka: true
    #是否从Eureka Server 抓取已有的注册信息,默认为:true 但节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版本

4、编写启动类

package com.cloud.springcloud;

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

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

5、编写实体类,接口

dao,mapper,service,controller 全部从cloud-provider-payment8001中直接复制过来即可。
mapper复制如图:
在这里插入图片描述
controller,service,dao复制如图:
在这里插入图片描述

6、服务调用测试

测试方法:
1、在cloud-provider-payment8001 控制层打印出当前服务的端口,来判断是调用的那台服务。
添加内容如下:
在这里插入图片描述
2、在cloud-provider-payment8002 控制层打印出当前服务的端口,来判断是调用的那台服务。
添加内容如下:
在这里插入图片描述

7、修改cloud-consumer-order80项目

单机版本编写时调用是写死的,所以需要进行修改。
如图所示:端口是写死的所以需要修改
在这里插入图片描述
1、将PAYMENT_URL的值修改成服务名次:
如图所示服务名称:在这里插入图片描述
修改完成后如图所示:
在这里插入图片描述

2、由于是用的服务的名称,调用服务时也不知道那台服务来处理请求,所以这里就出来来负载均衡配置
修改cloud-consumer-order80项目中ApplicationContextConfig类
修改如图所示:并通过 @LoadBalanced 注解开启客户端 负载均衡。
在这里插入图片描述

8、进行测试服务调用

测试结果如图所示:注意查看端口号的变化
在这里插入图片描述

9、完善显示设置

1、主机名称修改:
2、访问信息有IP信息提示
主要修改8001 与8002 两台服
分别在cloud-provider-payment8001, cloud-provider-payment8002 中修改application.yml 在此文件中加入如图所示:
在这里插入图片描述

 #Eureka 客户端配置
eureka:
  client:
    #表示是否将自己注册进Eureka Server中去,默认是true。
    register-with-eureka: true
    #是否从Eureka Server 抓取已有的注册信息,默认为:true 但节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版本
    #添加主机名称
  instance:
    instance-id: payment8001

修改后结果如图显示:
在这里插入图片描述

同上修改cloud-provider-payment8002
如图所示:在这里插入图片描述
设置访问IP显示:
同样在YAML文件中添加以下配置,如图所示:
在这里插入图片描述

10、最终结果:

如图所示:
在这里插入图片描述

八、DiscoveryClient对象的使用

在这里用cloud-provider-payment8001为列:
1、在cloud-provder-payment8001中PaymentController类里引用此对象
2、编写一个方法用来测试DiscoveryClient 对象获取服务列表
如图所示:
在这里插入图片描述

1、测试方法编写

@GetMapping(value = "/payment/discovery")
    public Object discovery() {
        List<String> services = discoveryClient.getServices();
        for (String element:services){
            log.info("*******element:"+element);
        }

        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance:instances){
            log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
        }
        return this.discoveryClient;
    }

2、添加注解

在主启动类上添加@EnableDiscoveryClient此注解
通过@EnableDiscoveryClient注解 让该应用注册为 Eureka 客户端应用, 以获得服务发现的能力
如图所示:
在这里插入图片描述

3、接口测试

测试地址:http://localhost:8001/payment/discovery
测试结果如图所示:
网页显示结果:
在这里插入图片描述
后台日志显示的结果:
在这里插入图片描述

Eureka自我保护机制

为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,EurekaServer 不立刻将EurekaClint服务从服务列表中删除。

什么是自我保护模式?

默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销实例(默认90秒)但是当网络分区故障发生(延时,卡顿,拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了–应为微服务本身其实是健康当,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时内丢失过多客户端时(可能发生来网络分区故障),那么这个节点就会进入自我保护模式。
在自我保护模式中,Eureka Server 会保护服务注册表中当信息,不会注销任何服务实例,使用自我保护模式,可以让Eureka集群更加当健壮,稳定
具体配置如下:

#Eureka 客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
eureka.instance.lease-renewa l-interval-in-seconds= 30
#Eureka 服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时剔除服务。 
eureka.instance.lease-expiration-duration-in-seconds= 90

九、Zookeeper服务注册与发现

Zookeeper 下载

通过wget下载zookeeper

#第一步:先安装wget 命令如下:
yum -y install wget
#第二步:安装好wget后,通过wegt 进行下载zookeeper安装包 如果地址失效去官方找:https://zookeeper.apache.org/releases.html
wget  https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.5.8/apache-zookeeper-3.5.8-bin.tar.gz
#第三步:通过ls或者ll命令查看有没有下载成功,下载成功则用如下命令进行解压
tar -xvf apache-zookeeper-3.5.8-bin.tar.gz #下载的zookeeper压缩包文件名称

十、cloud-provider-payment8004

1、创建项目

项目名称:cloud-provider-payment8004
创建方式如图所示:
在这里插入图片描述

2、修改POM文件

pom文件可以直接复制8001或者8002项目中的pom文件
需要替换一个jar包依赖,把Eureka依赖修改为 zookeeper依赖
具体pom内容如下:

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.23</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
<!--        zookeeper jar包依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
    </dependencies>

3、编写YAML文件

在resource文件下创建一个YAML文件
文件名称为:application.yml
编写内如下所示:

#编写服务端口号
server:
  port: 8004
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      #zookeeper服务地址配置
      connect-string: 10.168.8.100:2181

4、编写启动类

package com.cloud.springcloud;

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

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

5、编写业务类

controller类

package com.cloud.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@Slf4j
@RestController
public class PaymentController {
    @Value("${server.port}")
    private  String serverPort;
    @GetMapping(value = "/payment/zk")
    public String paymentzk(){
        return "springcloud with zookeeper "+serverPort+"\t"+ UUID.randomUUID().toString();
    }
}

6、启动zookeeper服务

#进入zookeeper的bin目录
cd bin
#启动zookeeper服务
sh zkServer.sh start #或者使用 ./zkServer.sh
#Error 错误信息
Error: JAVA_HOME is not set and java could not be found in PATH.
#解决方案,安装JDK 通过wget下载 jdk 命令如下
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u141-b15/336fa29ff2bb4ef291e347e091f7f4a7/jdk-8u141-linux-x64.tar.gz"
#解压jdk 命令如下
tar -xvf jdk-8u162-linux-x64.tar.gz
#配置环境变量 先进入jdk的bin目录
cd jdk1.8.0_162/bin
#查看当前目录地址 命令
pwd
#复制目录地址:/usr/local/src/jdk1.8.0_162/bin
#修改环境变量 命令如下
vim  /etc/profile
# 按键盘i字母进行编辑模式
i
#通过上下键光标移动到文件末尾,编辑如下值
export JAVA_HOME=/usr/local/src/jdk1.8.0_162
export PATH=${PATH}:${JAVA_HOME}/bin
#编辑好后,按esc进行退出编辑模式 ,进行保存 按住shift+:输入一下值wq 按回车键进行保存
wq
#重新加载配置文件
source /etc/proflie
#查看是否配置成功,输入查询版本号命令
java -version
#显示了版本号说明配置成功!如图所示

在这里插入图片描述
重新启动zookeeper

sh zkServer.sh start #或者 ./zkServer.sh start

查看zookeeper启动状态

sh zkServer.sh status

在这里插入图片描述
以上表示启动失败,我们需要修改一下配置文件,

#在zookeeper根目录下面配置创建两个文件夹data ,log
mkdir data log
#进入创建好到data目录复制一下路径
cd data
pwd
#/usr/local/src/apache-zookeeper-3.5.8-bin/data
#然后进zookeeper 配置文件夹下修改zoo.cfg
 cd ../conf/
 #复制一份配置文件
 cp  zoo_sample.cfg zoo.cfg
 #修改配置文件
 #修改dataDir路径
 dataDir=/usr/local/src/apache-zookeeper-3.5.8-bin/data
 #添加dataLogDir配置
 dataLogDir=/usr/local/src/apache-zookeeper-3.5.8-bin/log
 #最后保存 重新启动zookeeper 启动成功如图所示

在这里插入图片描述

7、关闭防火墙

如图所示:表示在尝试进行连接
在这里插入图片描述
用一下方法进行关闭:

sudo systemctl stop firewalld 临时关闭
sudo systemctl disable firewalld ,然后reboot 永久关闭
sudo systemctl status  firewalld 查看防火墙状态。

8、查看zookeeper注册情况

在这里插入图片描述
连接zookeeper命令

# 在zookeeper 的bin目录下
sh zkCli.sh 
#查看注册的服务
ls /
#查看注册信息ID
ls /services/cloud-provider-payment

十一、cloud-consumerzk-order80

1、创建项目

项目名称:cloud-consumerzk-order80
在这里插入图片描述

2、修改pom文件

注意事项:可以直接从cloud-consumer-order80项目中复制pom文件,只需要修改Eureka jar包依赖换成zookeeper jar包依赖

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>

3、编辑YAML文件

在resource资源文件下创建一个application.yml文件

server:
  port: 80

spring:
  application:
    name: cloud-consumer-order
  cloud:
    #注册到zookeeper地址
    zookeeper:
      connect-string: 10.168.8.100:2181

4、编写主启动类

package com.cloud.springcloud;

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

@EnableDiscoveryClient
@SpringBootApplication
public class OrderZKMain80 {

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

5、编写业务类

1、配置类编写

package com.cloud.springcloud.config;

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

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

2、编写Controller

package com.cloud.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@Slf4j
public class OrderZKController {
    public static final String INVOKE_URL="http://cloud-provider-payment";

    private RestTemplate restTemplate;
    @GetMapping(value = "/consumer/payment/zk")
    public String paymentInfo(){
        String result =restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
        return result;
    }
}

6、测试结果

在这里插入图片描述

十二、Consul服务注册与发现

Consul是一套开源的分布式服务器发现和配置管理系统,是由HashiCorp公司使用Go语言开发
提供了微服务系统中的服务治理,配置中心,控制总线等功能,这些功能,这些功能中的每个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。
它具有很多优点,包括:基于raft协议,比较简洁;支持健康检查,同时支持HTTP和DNS协议,支持跨数据中心的WAN集群,提供图形界面,跨平台,支持Linux ,mac,Windows。

1、Spring cloud Consul 具有一下特性

  • Service Discovery (服务的发现)
  • Health Checking (健康监测)
  • KV Store (KV存储)
  • Secure Service Communication (多数据中心)
  • Multi Datacenter (可视化Web界面)

2、consul下载地址

根据自己的电脑系统类型进行下载即可:
官方下载地址:https://www.consul.io/downloads

3、consul启动命令

consul agent -dev
#如果不清楚可以输入
consul -h
查看consul图形化页面,consul启动后在浏览器中输入如下地址:localhost:8500
consul 开启的默认访问端口8500

十三、创建服务提供者

1、创建cloud-provider-payment8006

如图所示:
在这里插入图片描述

2、修改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-actuator</artifactId>
        </dependency>
<!--        consul jar依赖引入-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3、编写YAML文件

在resource目录下创建一个application.yml文件

server:
  port: 8006
spring:
  application:
    name: cloud-provider-payment
#cloud-consul配置
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}

4、编写主启动类

package com.cloud.springcloud;

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

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

5、编写业务类

控制层Controller

package com.cloud.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@Slf4j
public class PaymentController {
    @Value("${server.port}")
    private  String serverPort;
    @GetMapping(value = "/payment/consul")
    public String paymentConsul(){
        return "springcloud with consul"+ serverPort+"\t"+ UUID.randomUUID().toString();
    }
}

6、测试结果

访问结果
在这里插入图片描述
注册结果

在这里插入图片描述

十四、创建服务消费者

1、创建cloud-consumer-consul-order80

在这里插入图片描述

2、修改pom文件

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3、编写YMAL文件

在resource文件夹下面创建一个application.yml文件

server:
  port: 80
spring:
  application:
    name: cloud-consul-order
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}

4、编写主启动类

package cloud.springcloud;

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

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

5、编写配置类

package cloud.springcloud.config;

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

@Configuration
public class ApplicationContextConfig {

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

6、编写业务逻辑

编写controller类

package cloud.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderConsulController {
    private  static final String INVOKE_URL="http://consul-provider-payment";
    
    @Resource
    private RestTemplate restTemplate;
    @GetMapping(value = "/consumer/payment/consul")
    public  String paymentInfo(){
        return  restTemplate.getForObject(INVOKE_URL+"/payment/consul",String.class);
    }
}

7、查看测试结果

1、查看注册结果如图所示:
在这里插入图片描述
2、查看访问结果如图所示:
在这里插入图片描述

十五、总结三种注册中心

1、CAP原则

在这里插入图片描述

定义:CAP原则又称CAP定理,指的是在一个分布式系统中、Consistency (一致性)、Availability (可用性)、Partitiontolerance(分区容错性),三者不可兼得。
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(例如:取一个值不能这会是a,过一会变成了b,想要确保数据一致性必须使用事务,而事务在分布式系统里很难实现。)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户的读写请求。(可用性一般使用负载均衡或者心跳检测加IP漂移来保证)
分区容忍性(P):分区容错性是指系统能够容忍节点之间的网络的故障。也就是说单台服务器或多台服务器出现网络问题后,其他服务依然能够正常提供服务。分区容忍性可以使用选举机制实现。
三种取舍策略:
CA:(一致性与可用性):满足了一致性可用性那么就不能满足分区容忍性,这样也就意味着放弃了系统的可扩展性了,也就是说分布式节点受到限制,没办法部署子节点,这样就违背了设计分布式架构的初衷了。
CP:(一致性与分区容忍性):满足了一致性分区容忍性那么就不能满足可用性,也就是说要保持强一致性,每个请求访问服务器之间需要保持强一致性,而由于P是分区容忍性所以会导致同步时间无限延长(也就是说要等服务器之间数据全部同步完后才能访问服务器) ,一旦发生网络故障或者消息丢失等情况,就要牺牲用户的体验感了。等待所有的数据全部一致后再让用户才能正常访问系统,这种设计CP原则系统其实不少,最为典型的分布式数据库,如Redis,HBase等,对于这些分布式数据库来说,数据的一致性是最基本的要求,因为如果连这个标准都达不到,那么直接采用关系型数据库就好,没必要再浪费资源来部署分布式数据库。
AP:(可用性与分区容忍性):要高可用并允许分区,则需要放弃一致性,一旦分区的产生,那么节点之间有可能会产生失联的情况。为了高可用只能用本地数据来提供服务,而这样会导致全局数据的不一致性。典型的应用就如某米的抢购手机场景,可能前几秒你浏览商品的时候页面提示是有库存的,当你选择完商品准备下单的时候,系统提示你下单失败,商品已售完。这其实就是先在 A(可用性)方面保证系统可以正常的服务,然后在数据的一致性方面做了些牺牲,虽然多少会影响一些用户体验,但也不至于造成用户购物流程的严重阻塞。

2、三种注册中心区别

组件语言CAP服务键康检查对外暴露接口Spring Cloud集成
EurekajavaAP可配置支持HTTP已集成
ConsulGoCP支持HTTP/DNS已集成
ZookeeperjavaCP支持客户端已集成

十六、Ribbon负载均衡服务调用

1、Ribbon的定义

Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer (简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。

2、LB负载均衡(Load Balance)是什么?

简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)。
常见的负载均衡软件Nginx,LVS,硬件F5等

3、Ribbon与Nginx 服务端负载均衡区别?

Nginx是服务器负载均衡,客户端所有请求都会给nginx实现转发请求。即负载均衡是由服务端实现端。
Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程调度技术。

4、手写负载均衡业务

在 cloud-consumer-order80 项目中springcloud包下创建一个lb包,在包中创建一个接口,命名为:LoadBalancer
在LoadBalancer接口中编写一个方法 ,代码如下:

package com.cloud.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;

public interface LoadBalancer {
    ServiceInstance instance(List<ServiceInstance> serviceInstances);
}

再在lb包中创建一个 LoadBalancer接口的实现类,命名为:LoadBalancerImpl 重写instance方法
具体内容如下:

package com.cloud.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class LoadBalancedImpl  implements  LoadBalancer{

    private  AtomicInteger atomicInteger=  new AtomicInteger(0);

    public  final int getAndIncrement(){
        int current;
        int next;
        do{
            current=this.atomicInteger.get();
            next=current>=Integer.MAX_VALUE?0:current+1;
        }while (!this.atomicInteger.compareAndSet(current,next));
        System.out.println("第几次访问:"+next);
        return  next;
    }
    
    @Override
    public ServiceInstance instance(List<ServiceInstance> serviceInstances) {
       int index= getAndIncrement()%serviceInstances.size();
        return serviceInstances.get(index);
    }
}

AtomicInteger类中主要实现了整型的原子操作,防止并发情况下出现异常结果,其内部主要依靠JDK 中的unsafe 类操作内存中的数据来实现的。volatile 修饰符保证了value在内存中其他线程可以看到其值得改变。CAS操作保证了AtomicInteger 可以安全的修改value 的值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值