• SpringCloud Eureka简单使用学习


    如下摘自《SpinrgCloud微服务架构开发实践》

    服务治理

    SpringCloud服务治理有两种选择,Consul和Neiflix的Eureka。
    Eureka是Netflix开源的一块服务治理产品,Spirng Cloud对其进行了二次封装,形成了Spirng Cloud Netflix子项目。Erueka提供了服务注册中心、服务发现客户端,以及注册服务的UI界面应用。在Eureka的视线中,节点之间相互平等,有部分注册中停止不会对整个应用造成影响,及时汲取中只剩下一个节点存活,也可以正常的治理服务。即使所有服务注册节点都宕机,Eureka客户端中所缓存的服务实例列表信息,也可以让服务消费者能够正常工作,从而保障微服务之间相互调用的健壮性和应用的弹性。

    客户端负载均衡

    SpringCloud通过对Netflix开源项目Ribbon封装,实现了客户端负载均衡,Ribbon默认与Eureka无缝整合,当客户端启动时,从Eureka服务器中获取一份服务注册列表并维护在本地,当服务消费者需要调用服务时,Ribbon就会根据负载均衡策略选择一个合适的服务提供者进行访问。SpringCloud通过集成Netflix的Feign项目,为开发者提供了声明式服务调用,从而简化了微服务之间的调用处理方式。并且默认Feign项目继承了Ribbon,使得声明式调用也支持客户端负责均衡功能。

    微服务容错,降级

    在SpirngCloud中,通过集成Netflix的子项目Hystrix,通过所提供的的@HystrixCommand注解可以为我们所开发的微服务提供容错,回退,降级等功能,Hystrix也默认集成到Feign子项目中。Hystrix是根据“断路器”模式而创建,当Hystrix监控到某服务单元发生故障之后,就会进入服务熔断chul,bing向调用方返回一个符合语气的服务降级处理(fallback),而不是长时间的等待或者抛出调用异常,从而保障服务调用方的香橙不会被长时间,不必要的占用,避免鼓掌在英语红中的蔓延造成的雪崩效应。Hystrix仪表盘炫目(Dashboard)可以监控各个服务调用所消耗的时间、请求书、成功率等。

    本测试使用版本

    SpringBoot: 2.6.2 

    SpringCloud: 2021.0.0

    Eureka服务注册中心

    maven配置

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.6.2</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.demo</groupId>
        <artifactId>service-discovery</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>service-discovery</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>2021.0.0</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    View Code

    除SpringBoot和SpringCloud基础版本号配置外,必须加上eureka-server的maven依赖,web模块依赖可以不加,如果不加则会用eureka-server默认依赖的web模块

    启动类

    package com.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class ServiceDiscoveryApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ServiceDiscoveryApplication.class, args);
        }
    
    }
    View Code

    必须加上@EnableEurekaServer注解

    参数配置

    server.port=9999
    eureka.instance.appname=eureka
    eureka.instance.hostname=127.0.0.1
    eureka.instance.prefer-ip-address=true
    ## 当前就是eureka注册服务中心,并且是单机版,不需要向eureka中注册当前服务,设置为false
    eureka.client.register-with-eureka=false
    ## 不需要从eureka注册服务中心拉取服务列表,设置为false
    eureka.client.fetch-registry=false
    ## eureka注册服务中心地址
    eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
    eureka.server.wait-time-in-ms-when-sync-empty=0
    eureka.server.enable-self-preservation=false
    View Code

    到此Eureka服务注册中心就搭建完成,启动后,访问地址http://127.0.0.1:9999/,即可访问到eureka注册管理界面,在其中可以看到注册过的服务等信息

    服务提供者

    maven配置

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.6.2</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.demo</groupId>
        <artifactId>service-product</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>service-product</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>2021.0.0</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    View Code

    除SpringBoot和SpringCloud基础版本号配置外,必须加上eureka-client的maven依赖,由于提供的为web服务,也需要加上web相关starter依赖

    controller

    package com.demo.controller;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.demo.entity.ResultEntity;
    
    @RestController
    @RequestMapping
    public class ServerController {
        private Logger logger = LoggerFactory.getLogger(ServerController.class);
        
        @RequestMapping("/getData/{id}")
        public Object getData(@PathVariable String id) {
            logger.info("server receive id: {}", id);
            return new ResultEntity(true, "result: "+id);
        }
    }
    View Code

    返回实体类

    package com.demo.entity;
    
    public class ResultEntity {
    
        private boolean success;
        private String msg;
    
        public ResultEntity(boolean success, String msg) {
            this.success = success;
            this.msg = msg;
        }
    
        public boolean isSuccess() {
            return success;
        }
    
        public void setSuccess(boolean success) {
            this.success = success;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
    }
    View Code

    启动类

    package com.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * 高版本可以不用使用@EnableDiscoveryClient
     * @author admin
     *
     */
    @SpringBootApplication
    //@EnableDiscoveryClient
    public class ServiceProductApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ServiceProductApplication.class, args);
        }
    
    }
    View Code

    参数配置

    ## 端口自动分配,如果自动分配会有影响,则可以指定一个端口,比如指定端口才能通过防火墙访问时,则需要指定端口
    server.port=0
    spring.application.name=service-provider
    eureka.client.register-with-eureka=true
    eureka.client.fetch-registry=false
    eureka.client.service-url.defaultZone=http://127.0.0.1:9999/eureka/
    View Code

    服务消费者

    maven配置

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.6.2</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.demo</groupId>
        <artifactId>service-consumer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>service-consumer</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <spring-cloud.version>2021.0.0</spring-cloud.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    View Code

    除SpringBoot和SpringCloud基础版本号配置外,必须加上eureka-client的maven依赖,web项目也需要加上web相关依赖,由于使用到了fegin,因此也需要加入feign相关的依赖。

    controller

    package com.demo.controller;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.demo.entity.ResultEntity;
    import com.demo.service.ConsumerService;
    
    @RestController
    @RequestMapping
    public class ConsumerController {
    
        private Logger logger = LoggerFactory.getLogger(ConsumerController.class);
        
        @Autowired
        private ConsumerService ConsumerService;
        
        @RequestMapping("/getData/{id}")
        public Object getData(@PathVariable String id) {
            logger.info("concumer id: {}", id);
            ResultEntity data = ConsumerService.getData(id);
            return data;
        }
    }
    View Code

    feign调用

    package com.demo.service;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import com.demo.entity.ResultEntity;
    import com.demo.service.callback.ConsumerServiceCallBack;
    
    @FeignClient(name = "SERVICE-PROVIDER", fallback = ConsumerServiceCallBack.class)
    public interface ConsumerService {
    
        /**
         * 此处不能返回Object,要么返回String,要么返回存在get set方法的实体对象或者map
         * @param id
         * @return
         */
        @RequestMapping("/getData/{id}")
        ResultEntity getData(@PathVariable String id);
    } 
    View Code

    fallback

    package com.demo.service.callback;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;
    import org.springframework.web.bind.annotation.PathVariable;
    
    import com.demo.entity.ResultEntity;
    import com.demo.service.ConsumerService;
    
    @Service
    public class ConsumerServiceCallBack implements ConsumerService{
    
        private Logger logger = LoggerFactory.getLogger(ConsumerServiceCallBack.class);
        
        @Override
        public ResultEntity getData(@PathVariable String id) {
            logger.error("call back id: {}", id);
            return new ResultEntity(false, "error");
        }
    
    }
    View Code

    接收实体类(与服务提供者的返回实体类对应)

    package com.demo.entity;
    
    public class ResultEntity {
    
        private boolean success;
        private String msg;
    
        public ResultEntity(boolean success, String msg) {
            this.success = success;
            this.msg = msg;
        }
    
        public boolean isSuccess() {
            return success;
        }
    
        public void setSuccess(boolean success) {
            this.success = success;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
    }
    View Code

    启动类

    package com.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @SpringBootApplication
    //@EnableDiscoveryClient
    @EnableFeignClients
    public class ServiceConsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ServiceConsumerApplication.class, args);
        }
    
    }
    View Code

    参数配置

    ## 端口自动分配
    server.port=8081
    spring.application.name=service-consumer
    eureka.client.register-with-eureka=false
    eureka.client.fetch-registry=true
    eureka.client.service-url.defaultZone=http://127.0.0.1:9999/eureka/
    View Code

    测试,先启动eureka注册中心,在启动服务提供者,最后启动服务消费者,界面访问:http://127.0.0.1:8081/getData/11,返回结果如下

    其中11为id,使用其他的值也行,会在result中原样返回。

    到此,eureka服务注册中,服务的注册与消费的一个完整的服务治理流程demo结束。

    注意事项:

    1、在低版本的SpringCloud中,服务器提供者和服务消费者都需要添加@EnableDiscoveryClient注解,在高版本中则不需要,SpringCloud则会根据引入的starter自动开启eureka客户端

    2、如果服务提供者返回的为一个字符串,只是使用Object接收远程获取到的结果,可能会出现如下异常:

    org.springframework.web.client.UnknownContentTypeException: Could not extract response:
    no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [text/plain;charset=UTF-8]

    可以改为使用实体对象或者map来接收,或者直接用字符串接收,如果使用实体对象来返回和接收数据,则需要给实体类添加上get和set方法,否则可能会出现如下异常

    Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]

    3、@EnableEurekaClient和@EnableDiscoveryClient都能够让注册中心发现,并扫描到该服务,其中前者只对Eureka有效,后者可以对Eureka,Zookeeper、Consul等注册中心有效;

    4、如果使用feign进行远程调用,在服务消费者一方一定要加上@EnableFeignClients,否则feign调用不通,另外如果去掉实现了自定义的fegin相关接口的实现类callback,则无法将fegin接口调用注入到controller中,服务启动时可能会出现如下错误

    Field ConsumerService in com.demo.controller.ConsumerController required a bean of type 'com.demo.service.ConsumerService' that could not be found.

  • 相关阅读:
    【禅道】禅道安装步骤
    软件测试学习路线
    【mysql】mysql数据库安装
    【用例】测试用例阶段总结
    【坑】自动化测试之Excel表格
    开始.....
    网络攻防
    PAT/查找元素习题集
    PAT/简单模拟习题集(二)
    PAT/简单模拟习题集(一)
  • 原文地址:https://www.cnblogs.com/qq931399960/p/15825840.html
Copyright © 2020-2023  润新知