IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringCloud系列(一)、服务注册中心Eureka基础 -> 正文阅读

[Java知识库]SpringCloud系列(一)、服务注册中心Eureka基础

作者:recommend-item-box type_blog clearfix

启动Eureka服务注册中心

1、微服务的注册中心

注册中心可以说是微服务架构中的“通讯录”,他记录了服务与服务地址之间的映射关系。在分布式架构中,所有的服务都会注册到这里,当一个服务需要调用其他服务时,在注册中心找到相应的服务地址即可调用。
在这里插入图片描述

1.1、注册中心的主要作用

服务注册中心是微服务架构中非常重要的一个组件,在微服务架构中主要起到了协调者的一个作用。注册中心一般包含如下几个功能:

1、服务发现:

  • 服务注册/反注册:保存服务提供者和服务调用者的信息;
  • 服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能;
  • 服务路由(可选):具有筛选整合服务提供者的能力。

2、服务配置:

  • 配置订阅:服务提供者和服务调用者订阅微服务相关的配置;
  • 配置下发:主动将配置推送给服务提供者和五福调用者。

3、服务健康检测:

  • 检测服务提供者的健康情况。

1.2、常见的注册中心

  • Zookeeper

    zookeeper是一个分布式服务框架,是Apache Hadoop的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题。如:统一命名服务状态同步服务集群管理分布式应用配置项的管理等
    简单来说:zookeeper = 文件系统 + 监听通知机制。

  • Eureka

    Eureka是在Java语言上编写的,基于Restful Api开发的服务注册与发现组件,SpringCloud Netflix中的重要组件。

  • Consul

    Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册的服务组件,采用Raft算法保证服务的一致性,且支持健康检查。

  • Nacos

    Nacos是一个更易于构建云原生应用的动态服务发现,配置管理和服务管理平台。
    简单来说:Nacos就是注册中心 + 配置中心的组合。
    提供简单易用的特性集,帮助我们解决微服务开发必会设计到的服务注册与发现、服务配置、服务管理等问题。
    Nacos还是Spring Cloud Alibaba组件之一,负责服务注册与发现。

1.3、常见注册中心的异同点

我们通过一张表格大致了解Eureka、Consul、Zookeeper之间的异同点,选择什么类型的服务注册与发现组件可以根据自身项目要求决定。

组件名语言CAP一致性算法服务健康检查对外暴露接口
EurekaJavaAP可配支持HTTP
ConsulGoCPRaft支持HTTP/DNS
ZookeeperJavaCPPaxos支持客户端
NacosJavaAPRaft支持HTTP

2、Eureka概述

2.1、Eureka的基础知识

Eureka是Netflix开发的服务发现框架,SpringCloud将它集成在自己的子项目spring-cloud-netflix中,实现SpringCloud的服务发现功能。
在这里插入图片描述
上述简要描述了Eureka的基础架构,由三个角色组成:

  • Eureka

    提供服务注册和发现

  • Service Provider

    服务提供方;
    将自身服务注册到Eureka注册中心,从而使服务消费方能够找到。

  • Service Consumer

    服务消费方;
    从Eureka注册中心获取注册服务列表,从而能够消费服务。

2.2、Eureka的交互流程与原理

在这里插入图片描述
上图来自Eureka官方的架构图,大致描述了Eureka集群的工作过程。图中包含的组件非常多,可能比较难以理解,下面各组件的介绍:

  • us-east-1c和us-east-1d和us-east-1e

    属于zone(分区),他们都属于us-east-1这个region(地区)

  • Apllication Service

    相当于服务提供者(属于客户端Eureka Client)

  • Application Cient

    相当于服务消费者(属于客户端Eureka Client)

  • Make Remote Call

    可以简单理解为调用Restful API

由上图可知,Eureka包含两个组件:Eureka Server 和 Eureka Client,它们的作用如下:

  • Eureka Client是一个Java客户端(包括服务提供者和消费者),用于简化与Eureka Server的交互;
  • Eureka Server是提供服务发现的能力,各个微服务启动时,会通过Eureka ClientEureka Server进行注册自己的信息(例如网络信息),Eureka Server会存储该服务的信息;
  • 微服务启动后,会周期性的向Eureka Server发送心跳(默认周期为30秒),以续约自己的在线信息。如果Eureka Server在一定时间内没有接收到某个微服务节点的心跳,Eureka Server将会注销该微服务的节点(默认检测时长为90秒);
  • 每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过复制的方式完成服务注册表的同步
  • Eureka Client会缓存Eureka Server中的信息,即使所有的Eureka Server节点都宕机,服务消费者依然可以使用缓存中的信息找到服务提供者。

综上所述,Eureka通过心跳检测健康检查客户端缓存等机制,提高了系统的灵活性、可伸缩性和可用性。

3、搭建Eureka注册中心案例

3.1、搭建Eureka服务中心

(1)、创建ebuy-eureka模块(为了后续方便,可直接建成SpringBoot项目)

  • 继承ebuy-parent模块

(2)在maven中引入eureka-server依赖坐标

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

此处依赖的版本号尽量与所继承的parent项目的spring-boot-starter-parent版本号保持相同, 如果不同的话,要保证版本尽量相差不大,因为目前更高版本的SpringBoot对于netflix-eureka-server的兼容性还不是很完善。
在这里插入图片描述
为了后续一步到位,此处还有一个坑,如果你使用的是JDK8,目前来说是没有这方面的问题;如果是JDK9及以上版本就有问题了,就是JDK9以后的版本中没有关于JAXB-API默认的类路径的配置,因为JAXB-API是java ee的一部分,从jdk9开始java引入了模块的概念, 可以使用模块命令–add-modles java.xml.bind引入jaxb-api,当然还有一种简单粗暴的方法,就是在pom文件中引入以下依赖,以激活jaxb-api应用接口。

启动ebuy-eureka会出现以下错误:

java.lang.TypeNotPresentException: Type javax.xml.bind.JAXBContext not present

解决上述JAXBContext 不存在的异常:

<!--解决java.lang.TypeNotPresentException: Type javax.xml.bind.JAXBContext not present-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>

(3) 配置application.yml

server:
  port: 9000 #端口号

eureka:
  instance: #eureka实例
    hostname: 127.0.0.1 #服务器ip地址
  client:
    register-with-eureka: false #是否将自己注册到注册中心(本身就监管所有服务,无需注册)
    fetch-registry: false #是否从注册中心获取服务列表(本身就监管所有服务,无需获取)
    serviceUrl: #此处有驼峰命名法的自动转换,也可以写成service-url,推荐使用驼峰命名
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#Eureka Client(客户端)与Eureka Server(服务端)进行交互的地址
serviceUrl: #承接上下文,才可以这样写
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

(4) 配置启动类

package com.ebuy;

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

@SpringBootApplication
@EnableEurekaServer //激活Eureka Server端配置
public class EbuyEurekaApplication {

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

@EnableEurekaServer注解: 激活Eureka Server端配置

3.2、服务注册中心管理后台

启动ebuy-eureka工程启动类,在地址栏输入地址localhost:9000,直接回车即可进入EurekaServer内置的管理控制台,显示效果如下,其实下图界面与dubbo-amdin的可视化界面虽然画面不同,但是功能基本是一样的,同样是做注册中心的监管工作:
在这里插入图片描述

4、客户端服务注册到Eureka注册中心

4.1、商品模块服务注册

4.1.1、创建ebuy-product模块(为了后续方便,可直接建成SpringBoot项目)

  • 继承ebuy-parent模块

4.1.2、在maven中引入eureka-client客户端相关依赖坐标

        <!--springcloud公共类依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
        </dependency>

        <!--eureka注册中心客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!--mybatis整合springboot启动器-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <!--mysql连接依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

4.1.3、在com.ebuy.product包下创建pojo、mapper、service、controller层

  • pojo层创建实体类EasybuyProduct

    package com.ebuy.product.pojo;
    
    import lombok.Data; /*代表自动生成getter和setter方法*/
    import lombok.ToString;/*代表自动生成toString方法*/
    import java.io.Serializable;
    import java.math.BigDecimal;
    
    @Data
    @ToString
    public class EasybuyProduct implements Serializable {
    
        private Long epId;
    
        private String epName;
    
        private String epDescription;
    
        private BigDecimal epPrice;
    
        private Long epStock;
    
        private Long epcId;
    
        private Long epcChildId;
    
        private String epFileName;
    
        private static final long serialVersionUID = 1L;
    }
    
  • 上述EasyBuyProduct实体类中使用了两个注解@Data和@ToString,分别代表自动生成getter、setter方法和toString()方法,这种方式使用的是lombok插件,可以极大的提升实体类的开发效率和节省编码空间。

  • 第一步:首先在settings的plugins中下载插件:lombok,安装后注意要重启IDEA才能生效:
    在这里插入图片描述

  • 第二步:在ebuy-parent父级模块中导入lombok依赖坐标,后续只要继承ebuy-parent的模块,实体类都可以直接使用注解:

    		<!--lombok注解依赖-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.4</version>
                <scope>provided</scope>
            </dependency>
    
  • 这样上述实体类上的注解就可以使用了!

  • 在mapper层创建EasyBuyProductMapper接口:

    package com.ebuy.product.mapper;
    
    import com.ebuy.product.pojo.EasybuyProduct;
    
    public interface EasybuyProductMapper {
    
        /**
         * 根据商品id查询商品信息
         * @param epId
         * @return
         */
        EasybuyProduct selectByPrimaryKey(Long epId);
    }
    
  • 在resources目录下新建com/ebuy/product/mapper目录,并在其下新建EasyBuyProductMapper.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.ebuy.product.mapper.EasybuyProductMapper" >
      <resultMap id="BaseResultMap" type="com.ebuy.product.pojo.EasybuyProduct" >
        <id column="ep_id" property="epId" jdbcType="DECIMAL" />
        <result column="ep_name" property="epName" jdbcType="VARCHAR" />
        <result column="ep_description" property="epDescription" jdbcType="VARCHAR" />
        <result column="ep_price" property="epPrice" jdbcType="DECIMAL" />
        <result column="ep_stock" property="epStock" jdbcType="DECIMAL" />
        <result column="epc_id" property="epcId" jdbcType="DECIMAL" />
        <result column="epc_child_id" property="epcChildId" jdbcType="DECIMAL" />
        <result column="ep_file_name" property="epFileName" jdbcType="VARCHAR" />
      </resultMap>
    
      <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
        select ep_id, ep_name, ep_description, ep_price, ep_stock, epc_id, epc_child_id, ep_file_name from EASYBUY_PRODUCT
        where ep_id = #{epId,jdbcType=DECIMAL}
      </select>
    
    </mapper>
    
  • 在service层创建EasybuyProductService业务逻辑层接口(和mapper层保持一致即可):

    package com.ebuy.product.service;
    
    import com.ebuy.product.pojo.EasybuyProduct;
    
    /**
     * 业务逻辑层接口
     */
    public interface EasybuyProductService {
    	/**
         * 根据商品id查询商品信息
         * @param epId
         * @return
         */
        EasybuyProduct selectByPrimaryKey(Long epId);
    
    }
    
  • 在service.impl层创建EasyBuyProductServiceImpl实现类:

    package com.ebuy.product.service.impl;
    
    import com.ebuy.product.pojo.EasybuyProduct;
    
    @Service
    @SuppressWarnings("all")
    public class EasybuyProductServiceImpl implements EasybuyProductService {
    
    	/**
         * 调用mapper层接口
         */
        @Autowired
        EasybuyProductMapper easybuyProductMapper;
    
        @Override
        public EasybuyProduct selectByPrimaryKey(Long epId) {
            return easybuyProductMapper.selectByPrimaryKey(epId);
        }
     }
    
  • 在controller层新建ProductContoller:

    package com.ebuy.product.controller;
    
    import com.ebuy.product.pojo.EasybuyProduct;
    import com.ebuy.product.service.EasybuyProductService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping("/product")
    public class ProductController {
    
    	@Autowired
    	private EasybuyProductService productService;
    
    	@RequestMapping(value = "/{id}",method = RequestMethod.GET)
    	public EasybuyProduct findById(@PathVariable Long id) {
    		EasybuyProduct product = productService.selectByPrimaryKey(id);
     		return product;
    	}
    }
    

4.1.4、配置application.yml文件


server:
  port: 9011 #端口号

spring:
  application:
    name: ebuy-product #商品模块服务名称
  datasource:
    username: root #数据库用户名
    password: root #数据库密码
    driver-class-name: com.mysql.jdbc.Driver #mysql加载驱动
    url: jdbc:mysql://localhost:3306/ebuy?useUnicode=true&characterEncoding=utf8

mybatis:
  type-aliases-package: com.ebuy.product.pojo  #mybatis简化pojo实体类别名
  mapper-locations: com/ebuy/product/mapper/*.xml #mapper映射文件路径

logging:
  level:
    com.ebuy: DEBUG #日志级别

eureka:
  client:
    serviceUrl: #上述配置的ebuy-server的地址及端口
      defaultZone: http://127.0.0.1:9000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册(在注册中心显示名字以ip地址显示)

4.1.5、修改启动类添加服务注册注解

package com.ebuy;

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

@SpringBootApplication
@MapperScan("com.ebuy.product.mapper")
//@EnableEurekaClient  开启Eureka客户端
//@EnableDiscoveryClient  开启服务发现客户端
public class EbuyProductApplication {

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

从Spring Cloud Edgware版本开始, @EnableDiscoveryClient@EnableEurekaClient 可省略。只需加上相关依赖,并进行相应配置,即可将客户端微服务注册到服务发现组件上,但是上述的EurekaServer服务的启动类上必须要加上注解@EnableEurekaServer,表明当前服务是Eureka服务注册中心。

4.1.6、启动EbuyProductApplication 启动类向Eureka注册商品服务

在这里插入图片描述

4.1.7、在地址栏访问controller层Restful接口地址http://localhost:9011/product/816753,火狐浏览器可以解析JSON数据,正合咱意:

在这里插入图片描述

4.2、订单模块服务注册(步骤和上述商品微服务基本一致)

4.2.1、创建ebuy-order模块(为了后续方便,可直接建成SpringBoot项目)

  • 继承ebuy-parent模块

4.2.2、引入eureka-client客户端依赖

		<!--springcloud相关依赖公共类-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
        </dependency>
        <!--springcloud 注册中心eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

4.2.3、同样新建pojo、mapper、service、controller层

  • 在mapper层新建EasyBuyOrderMapper接口
  • 在service层新建EasyBuyOrderService接口(和Mapper层保持一致即可)
  • 在service.impl包下新建EasyBuyOrderServiceImpl实体类
  • 在controller层新建OrderController类

4.2.4、配置application.yml文件

server:
  port: 9012 #端口号
spring:
  application:
    name: ebuy-order #服务名
logging:
  level:
    cn.ebuy: DEBUG

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:9000/eureka/
  instance:
    prefer-ip-address: true   #使用ip地址注册(在注册中心显示名字以ip地址显示)

4.2.5、修改启动类添加服务注册注解

package com.ebuy.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
//@EnableEurekaClient  开启Eureka客户端
//@EnableDiscoveryClient  开启服务发现客户端
public class EbuyOrderApplication {

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

4.2.5、启动EbuyOrderApplication 启动类向Eureka注册服务

在这里插入图片描述

5、跨服务调用

上述编写了基础的微服务,均已注册到了Eureka注册中心中。
在这里插入图片描述

现在有个需求,用户在下订单时需要调用商品微服务获取商品数据,通过上述案例我们应该知道这是跨服务模块之间的调用,细心的伙子肯定看到了上述我们在商品的controller层提供了供他人调用的HTTP接口,并采用的是Restful风格,所以可以在下订单的时候使用http请求的相关工具类完成,如常见的HttpClientOkHttp

其实spring还为我们提供了一个工具类RestTemplate

5.1、RestTemplate介绍

Spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了Restful的标准,我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用Restful服务的方式。

在Spring应用程序中访问第三方Rest服务与使用Spring RestTemplate类有关。RestTemplate类的设计原则与其他Spring模板类(eg:JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。

RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为,(eg:Apache HttpComponents、Netty或者OKHttp)等其他HTTP library。

考虑到RestTemplate类是为了调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了,后者是HTTP协议的方法:HEAD、POST、PUT、DELETE和OPTIONS

RestTemplate类具有以下方法:

  • headForHeaders()
  • getForObject()
  • postForObject()
  • put()
  • delete()

5.2、RestTemplate方法介绍

该模板类的主要切入点为以下几个方法(并对应这HTTP的六个主要方法)
在这里插入图片描述

5.3、通过RestTemplate调用微服务

现有个需求,用户在下订单时需要调用商品微服务获取商品数据,这个时候就需要在订单模块中调用商品模块。

(1)首选在pojo层也新建一个EasyBuyProduct实体类,用于跨服务调用接收结果:

	package com.ebuy.order.pojo;
	
	import lombok.Data;
	import lombok.ToString;
	import java.io.Serializable;
	import java.math.BigDecimal;
	
	@Data
	@ToString
	public class EasybuyProduct implements Serializable {
	
	    private Long epId;
	
	    private String epName;
	
	    private String epDescription;
	
	    private BigDecimal epPrice;
	
	    private Long epStock;
	
	    private Long epcId;
	
	    private Long epcChildId;
	
	    private String epFileName;
	
	    private static final long serialVersionUID = 1L;
	}

(2)在ebuy-order的主启动类EbuyOrderApplication处配置RestTemplate,在服务启动的时候即将RestTemplate交给spring容器管理:

package com.ebuy.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
//@EnableEurekaClient  开启Eureka客户端
//@EnableDiscoveryClient  开启服务发现客户端
public class EbuyOrderApplication {

    /**
     * 配置RestTemplate交给spring管理
     * @return
     */
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

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

(3)在OrderController类中先注入RestTemplate类,然后编写调用product模块的方法:

package com.ebuy.order.controller;


import com.ebuy.order.pojo.EasybuyProduct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;

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

    @Autowired
    RestTemplate restTemplate;

    /**
     * 直接跨项目调用
     * @param id
     * @PathVariable 将restful中的参数id映射到形参列表
     * @return
     */
    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    public EasybuyProduct findById(@PathVariable Long id) {
        EasybuyProduct easybuyProduct=new EasybuyProduct();
        //通过restTemplate类的方法getForObejct调用product的Rest服务,并接收返回值
        easybuyProduct=restTemplate.getForObject("http://127.0.0.1:9011/product/"+id,EasybuyProduct.class);
       return easybuyProduct;
    }

}

(4)启动ebuy-prodcut和ebuy-order两个服务,在地址栏访问http://localhost:9012/order/816753
在这里插入图片描述
上述结果显示说明ebuy-order模块成功调用ebuy-product的rest服务,并响应了结果!

5.4、RestTemplate调用Rest微服务的弊端

上述使用RestTemplate类的方法调用到了商品微服务的RESTFul API接口,但是我们可以很明显的看出,提供者的网络地址(ip,port)等被硬编码到了代码中,这种做法存在许多问题:

  • 应用场景有局限
  • 无法动态调整

5.5、解决RestTemplate硬编码存在的问题

需要通过注册中心动态的对服务注册服务发现
EurekaClient的注册,心跳及服务器上的注册信息获取在com.netflix.discovery.DiscoveryClient.initScheduledTasks()方法中实现。

DiscoveryClient默认获取服务器注册信息 间隔30秒,心跳时间30秒,Client启动以后40往服务器发送注册信息。

在OrderController类中使用DiscoveryClient重新编写服务调用:

package com.ebuy.order.controller;


import com.ebuy.order.pojo.EasybuyProduct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

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

    /**
     * 直接通过restTemplate调用远程服务,过于硬编码,不够灵活;
     * 通过DiscoveryClient默认获取服务器注册信息,
     * 动态调动所需要的服务(动态获取ip地址和端口)
     */
    @Autowired
    private DiscoveryClient discoveryClient;


    @RequestMapping(value = "/dc/{id}",method = RequestMethod.GET)
    public EasybuyProduct findDcById(@PathVariable Long id) {
        //所要调用的服务名
        List<ServiceInstance> list=discoveryClient.getInstances("ebuy-product");
        //我们目前只启动了一个服务,所以直接get(0)获取第一个服务即可
        ServiceInstance serviceInstance=list.get(0);
        /**
         * serviceInstance.getHost() 获取服务ip(动态)
         * serviceInstance.getPort() 获取服务端口(动态)
         */
        EasybuyProduct  easybuyProduct=restTemplate.getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/"+id,EasybuyProduct.class);
        return  easybuyProduct;
    }
}

我们在上述的两个微服务中已经配置了eureka-client相关配置,此时我们需要先启动EurekaServer服务注册中心,然后再启动eureka-client(product、order)两个客户端服务。

启动成功后,在浏览器地址栏访问地址http://localhost:9000/
在这里插入图片描述
说明客户端服务(product提供者和order消费者)已经成功注册到eureka注册中心了。
然后在地址栏访问http://localhost:9012/order/dc/816753
在这里插入图片描述
动态调用成功,妥!!!

5.6、Eureka的自我保护机制

微服务第一次注册成功之后,每30秒会发送一次心跳将服务的实例信息注册到中心。通过EurekaServer该实例仍然存在。如果超过90秒没有发送更新,则服务器将从注册信息中将此服务剔除。

Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于80%,如果出现低于80%的情况(在单机调试的时候很容易满足,实际在生产环境中是由于网咯不稳定导致的),Eureka Server会将当前的实例注册信息保护起来,同时提示一串红字警告。保护模式主要用于一组Eureka Client客户端和Eureka Server服务端之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其注册表中的信息,不再删除服务注册信息中的数据(也就是不会注销任何微服务)。

验证完自我保护机制开启后,并不会马上呈现在web上,而是你人需等待5分钟(可以通过在yml文件中配置如下)

eureka:
  server:
    wait-time-in-ms-when-sync-empty: 5  #默认为5分钟

即5分钟后再次刷新注册中心可视化监管界限会出现以下提示信息:
在这里插入图片描述
也可以关闭自我保护机制:

  server:
    enable-self-preservation: false #关闭自我保护机制

好了,今先到这吧!!!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:11:30  更:2021-09-14 13:12:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:12:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码