SpringCloud - Spring Cloud Netflix 之 Eureka,Ribbon

Posted MinggeQingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud - Spring Cloud Netflix 之 Eureka,Ribbon相关的知识,希望对你有一定的参考价值。

阅读本文前可先参考 

SpringCloud - Spring Cloud根/父项目,开发准备(二)_MinggeQingchun的博客-CSDN博客

我们首先来看下不需要注册服务中心,服务消费者 直接调用 服务提供者

一、服务消费者 直接 访问 服务提供者

1、服务提供者

1、新建一个springboot Module(springcloud-1-noregistry-provider),设置父项目(服务提供者)

2、添加 web,mysql,mybatis依赖,以及处理资源resoureces,java等插件

<!--继承统一的父项目-->
    <parent>
        <groupId>com.company</groupId>
        <artifactId>springcloud-demo</artifactId>
        <version>1.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.company</groupId>
    <artifactId>springcloud-1-noregistry-provider</artifactId>
    <version>1.0.0</version>

    <name>springcloud-1-noregistry-provider</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring web 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- MySQL的jdbc驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--mybatis起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

    </dependencies>

    <build>

        <!--处理资源目录-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>

            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <!--mybatis代码自动生成插件-->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.6</version>
                <configuration>
                    <!--配置文件的位置: 在项目的根目录下,和src平级的-->
                    <configurationFile>GeneratorMapper.xml</configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、application.prperties配置文件中配置访问端口9001,以及 mysql数据库等信息

server.port=9001

#设置mysql数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin123456

4、可使用代码自动生成响应的mapper,model,service等包以及响应类

public class Goods 

    private Integer goodId;
    private String goodName;
    private String goodNameDesc;
    private BigDecimal goodPrice;
    private String goodImgUrl;
    private Integer goodStore;
    private Date startTime;
    private Date endTime;

    public Integer getGoodId() 
        return goodId;
    

    public void setGoodId(Integer goodId) 
        this.goodId = goodId;
    

    public String getGoodName() 
        return goodName;
    

    public void setGoodName(String goodName) 
        this.goodName = goodName;
    

    public String getGoodNameDesc() 
        return goodNameDesc;
    

    public void setGoodNameDesc(String goodNameDesc) 
        this.goodNameDesc = goodNameDesc;
    

    public BigDecimal getGoodPrice() 
        return goodPrice;
    

    public void setGoodPrice(BigDecimal goodPrice) 
        this.goodPrice = goodPrice;
    

    public Integer getGoodStore() 
        return goodStore;
    

    public void setGoodStore(Integer goodStore) 
        this.goodStore = goodStore;
    

    public String getGoodImgUrl() 
        return goodImgUrl;
    

    public void setGoodImgUrl(String goodImgUrl) 
        this.goodImgUrl = goodImgUrl;
    

    public Date getStartTime() 
        return startTime;
    

    public void setStartTime(Date startTime) 
        this.startTime = startTime;
    

    public Date getEndTime() 
        return endTime;
    

    public void setEndTime(Date endTime) 
        this.endTime = endTime;
    

    @Override
    public String toString() 
        return "Goods" +
                "goodId=" + goodId +
                ", goodName='" + goodName + '\\'' +
                ", goodNameDesc='" + goodNameDesc + '\\'' +
                ", goodPrice=" + goodPrice +
                ", goodStore='" + goodStore + '\\'' +
                ", goodImgUrl='" + goodImgUrl + '\\'' +
                ", startTime=" + startTime +
                ", endTime=" + endTime +
                '';
    



@Mapper
public interface GoodsMapper 
    List<Goods> selectAllGoods();



@Service
public class GoodsServiceImpl implements GoodsService 

    @Autowired
    private GoodsMapper goodsMapper;

    public List<Goods> getAllGoods() 
        return goodsMapper.selectAllGoods();
    

    public Goods getGoodsById(Integer goodsId) 
        return goodsMapper.selectByPrimaryKey(goodsId);
    

    public int decrByStore(Integer goodsId, Integer buyNum) 
        return goodsMapper.updateByStore(goodsId, buyNum);
    
<?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.company.mapper.GoodsMapper">
    <resultMap id="BaseResultMap" type="com.company.model.Goods">
        <id column="good_id" jdbcType="INTEGER" property="goodId"/>
        <result column="good_name" jdbcType="VARCHAR" property="goodName"/>
        <result column="good_name_desc" jdbcType="VARCHAR" property="goodNameDesc"/>
        <result column="good_price" jdbcType="DECIMAL" property="goodPrice"/>
        <result column="good_img_url" jdbcType="VARCHAR" property="goodImgUrl"/>
        <result column="good_store" jdbcType="INTEGER" property="goodStore"/>
        <result column="start_time" jdbcType="TIMESTAMP" property="startTime"/>
        <result column="end_time" jdbcType="TIMESTAMP" property="endTime"/>
    </resultMap>
    <sql id="Base_Column_List">
        good_id, good_name, good_name_desc, good_price, good_store,good_img_url, start_time, end_time
    </sql>

    <select id="selectAllGoods" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from goods
    </select>

    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from goods
        where good_id = #goodId,jdbcType=INTEGER
    </select>

    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
        delete
        from goods
        where good_id = #goodId,jdbcType=INTEGER
    </delete>

    <insert id="insert" parameterType="com.company.model.Goods">
        insert into goods (good_id, good_name, good_price,good_store)
        values (#goodId,jdbcType=INTEGER, #goodName,jdbcType=VARCHAR, #goodPrice,jdbcType=DECIMAL,
                #goodStore,jdbcType=INTEGER)
    </insert>

    <insert id="insertSelective" parameterType="com.company.model.Goods">
        insert into goods
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="goodId != null">
                good_id,
            </if>
            <if test="goodName != null">
                good_name,
            </if>
            <if test="goodPrice != null">
                good_price,
            </if>
            <if test="goodStore != null">
                good_store,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="goodId != null">
                #goodId,jdbcType=INTEGER,
            </if>
            <if test="goodName != null">
                #goodName,jdbcType=VARCHAR,
            </if>
            <if test="goodPrice != null">
                #goodPrice,jdbcType=DECIMAL,
            </if>
            <if test="goodStore != null">
                #goodStore,jdbcType=INTEGER,
            </if>
        </trim>
    </insert>
    <update id="updateByPrimaryKeySelective" parameterType="com.company.model.Goods">
        update goods
        <set>
            <if test="goodName != null">
                good_name = #goodName,jdbcType=VARCHAR,
            </if>
            <if test="goodPrice != null">
                good_price = #goodPrice,jdbcType=DECIMAL,
            </if>
            <if test="goodStore != null">
                good_store = #goodStore,jdbcType=INTEGER,
            </if>
        </set>
        where good_id = #goodsId,jdbcType=INTEGER
    </update>
    <update id="updateByPrimaryKey" parameterType="com.company.model.Goods">
        update goods
        set good_name  = #goodName,jdbcType=VARCHAR,
            good_price = #goodPrice,jdbcType=DECIMAL,
            good_store = #goodStore,jdbcType=INTEGER
        where good_id = #goodsId,jdbcType=INTEGER
    </update>

    <update id="updateByStore">
        update goods
        set good_store = good_store - #buyNum,jdbcType=INTEGER
        where good_id = #goodsId,jdbcType=INTEGER
    </update>
</mapper>

5、创建服务提供者访问方法,基于RESTFUL风格

@RestController
public class GoodsController 

    @Autowired
    private GoodsService goodsService;

    @GetMapping(value = "/service/goodList")
    public List<Goods> goodList()
        List<Goods> goodsList = goodsService.getAllGoods();

        System.out.println("查询商品列表成功:");
        for (Goods good:goodsList) 
            System.out.println("查询商品:"+ good);
        
        return goodsList;
    

6、启动springboot启动类,访问应用,测试能否正常运行

http://localhost:9001/service/goodList

2、服务消费者

1、新建一个springboot Module(springcloud-1-noregistry-consumer),设置父项目 (服务消费者)

2、添加 web依赖

<!--继承统一的父项目-->
    <parent>
        <groupId>com.company</groupId>
        <artifactId>springcloud-demo</artifactId>
        <version>1.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.company</groupId>
    <artifactId>springcloud-1-noregistry-consumer</artifactId>
    <version>1.0.0</version>

    <name>springcloud-1-noregistry-consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring web 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、application.prperties配置文件中配置访问端口8081

4、创建一个RestConfig配置类,创建RestTemplate

RestTemplate

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

@Configuration
public class RestConfig 
    @Bean
    public RestTemplate restTemplate () 
        return new RestTemplate();
    

5、创建服务消费者访问方法,基于RESTFUL风格

@RestController
public class GoodsController 
    private final String GOODS_SERVICE_URL = "http://localhost:9001/service/goodList";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "/springcloud/goodList")
    public @ResponseBody Object getGoodList()
        //调用远程的一个controller(Restful风格调用)
        ResponseEntity<Object> responseEntity = restTemplate.getForEntity(GOODS_SERVICE_URL, Object.class);

        return responseEntity.getBody();
    

6、启动springboot启动类,访问应用,测试能否正常运行 http://localhost:8081/springcloud/goodList

二、Eureka 服务注册中心

通过手动指定每个服务来实现调用,相当低效,当服务接口增多,手动指定接口地址变得难以维护

Spring Cloud(特指 Spring Cloud Netflix) 提供了多种服务注册与发现的实现方式,如:Eureka、Consul、Zookeeper

Spring Cloud(特指 Spring Cloud Netflix)支持得最好的是 Eureka,其次是 Consul,再次是 Zookeeper;当然后续还会说到 Spring Cloud Alibaba的 Nacos

服务注册

服务注册:将服务所在主机、端口、版本号、通信协议等信息登记到注册中心上

服务发现

服务发现:服务消费者向注册中心请求已经登记的服务列表,然后得到某个服务的主机、端口、版本号、通信协议等信息,从而实现对具体服务的调用;

Eureka

Eureka 是 Netflix 公司开发的一款开源的服务注册与发现组件

Spring Cloud 将 Eureka 与 Netflix 中的其他开源服务组件(例如 Ribbon、Feign 以及 Hystrix 等)一起整合进 Spring Cloud Netflix 模块中,整合后的组件全称为 Spring Cloud Netflix Eureka。

Eureka 是 Spring Cloud Netflix 模块的子模块,它是 Spring Cloud 对 Netflix Eureka 的二次封装,主要负责 Spring Cloud 的服务注册与发现功能。

Spring Cloud 使用 Spring Boot 思想为 Eureka 增加了自动化配置,开发人员只需要引入相关依赖和注解,就能将 Spring Boot 构建的微服务轻松地与 Eureka 进行整合。

1、Spring Cloud Netflix 架构图

Service Provider: 暴露服务的服务提供方

Service Consumer:调用远程服务的服务消费方。

EureKa Server: 服务注册中心和服务发现中心

2、Eureka 两大组件

Eureka 采用 CS(Client/Server,客户端/服务器) 架构,它包括以下两大组件:

Eureka Server:Eureka 服务注册中心,主要用于提供服务注册功能。当微服务启动时,会将自己的服务注册到 Eureka Server。Eureka Server 维护了一个可用服务列表,存储了所有注册到 Eureka Server 的可用服务的信息,这些可用服务可以在 Eureka Server 的管理界面中直观看到。

Eureka Client:Eureka 客户端,通常指的是微服务系统中各个微服务,主要用于和 Eureka Server 进行交互。在微服务应用启动后,Eureka Client 会向 Eureka Server 发送心跳(默认周期为 30 秒)。若 Eureka Server 在多个心跳周期内没有接收到某个 Eureka Client 的心跳,Eureka Server 将它从可用服务列表中移除(默认 90 秒)。

注:“心跳”指的是一段定时发送的自定义信息,让对方知道自己“存活”,以确保连接的有效性。大部分 CS 架构的应用程序都采用了心跳机制,服务端和客户端都可以发心跳。通常情况下是客户端向服务器端发送心跳包,服务端用于判断客户端是否在线。

1、Eureka注册服务端

1、新建一个springboot Module(springcloud-3-service-eureka),设置父项目(服务注册中心)

2、添加 web,eureka-server 依赖

添加 eureka server 的依赖!!!spring-cloud-starter-netflix-eureka-server

<!--Spring Cloud 的 eureka-server 起步依赖--> 
<dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> 
</dependency> 
<!--继承统一的父项目-->
    <parent>
        <groupId>com.company</groupId>
        <artifactId>springcloud-demo</artifactId>
        <version>1.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.company</groupId>
    <artifactId>springcloud-3-service-eureka</artifactId>
    <version>1.0.0</version>

    <name>springcloud-3-service-eureka</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring web 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--Spring Cloud 的 eureka-server 起步依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、application.prperties配置文件中配置访问端口8761,以及配置 Eureka服务注册中心信息

#内嵌Tomcat端口
server.port=8761

#设置该服务注册中心的hostname
eureka.instance.hostname=localhost
#由于目前创建的应用是一个服务注册中心,而不是普通应用;默认情况下,这个应用会向注册中心(它自己)注册自己,设置FALSE表示禁止自己向自己注册的默认行为
eureka.client.register-with-eureka=false
#表示不去从服务端检索其他服务信息,因为自己就是服务端,服务注册中心本身职责就是维护服务实例,不需要去检索其他服务
eureka.client.fetch-registry=false
#指定服务注册中心的位置  eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

4、在 Spring Boot 的入口类上添加一个@EnableEurekaServer 注解,开启 Eureka 注册中心服务端

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer //开启Eureka服务端
@SpringBootApplication
public class EurekaApplication 

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

5、启动 SpringBoot 程序,main 方法运行,浏览器输入访问

http://localhost:8761/

Eureka控制面板界面如下

Eureka控制面板界面详细参数可参考 https://blog.csdn.net/MinggeQingchun/article/details/125261048 

2、Eureka注册服务提供者

1、新建一个springboot Module(springcloud-3-service-eureka-provider),设置父项目(服务提供者)

2、添加 web,mysql,mybatis,springcloud的common公共服务,springboot自动热部署,spring-cloud-starter-netflix-eureka-client等 依赖,以及处理资源resoureces,java等插件

eureka 客户端的依赖!!!spring-cloud-starter-netflix-eureka-client

<!--spring-cloud-starter-netflix-eureka-client-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--继承统一的父项目-->
    <parent>
        <groupId>com.company</groupId>
        <artifactId>springcloud-demo</artifactId>
        <version>1.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.company</groupId>
    <artifactId>springcloud-3-service-eureka-provider</artifactId>
    <version>1.0.0</version>

    <name>springcloud-3-service-eureka-provider</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring web 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- MySQL的jdbc驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--mybatis起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <!--依赖统一的springcloud-service-commons项目-->
        <dependency>
            <groupId>com.company</groupId>
            <artifactId>springcloud-2-service-common</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!-- springboot 开发自动热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

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

    </dependencies>

    <build>

        <!--处理资源目录-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>

            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>

        <plugins>

            <!--spring boot提供的编译、打包的Maven插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、application.prperties配置文件中配置访问端口9001,mysql数据库,以及 服务名称 和 eureka注册中心 等信息

server.port=9001

#设置应用名称,对应Eureka控制台下 DS Replicas 的 Application
spring.application.name=springcloud-3-service-eureka-provider

#设置mysql数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin123456

#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
eureka.instance.lease-renewal-interval-in-seconds=5
#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
eureka.instance.lease-expiration-duration-in-seconds=10
#告诉服务端,服务实例以IP作为链接,不是取机器名
eureka.instance.prefer-ip-address=false

#注册服务实例名称
eureka.instance.instance-id=springcloud-3-service-eureka-provider
#注册中心的链接地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

注:

这里需要配置一下应用名称,对应Eureka控制台下 DS Replicas 的 Application

#设置应用名称,对应Eureka控制台下 DS Replicas 的 Application
spring.application.name=springcloud-3-service-eureka-provider

如果没设置

设置了应用名称

4、在 Spring Boot 的启动类中,添加@EnableEurekaClient 注解,表明是一个 eureka 客户端,让服务提供者可以连接 eureka 注册中心

@EnableEurekaClient  //开启 Eureka client服务
@SpringBootApplication
public class Eureka3ProviderApplication 

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

5、可使用代码自动生成响应的mapper,model,service等包以及响应类(可放在公共服务Module common中)

public class Goods 

    private Integer goodId;
    private String goodName;
    private String goodNameDesc;
    private BigDecimal goodPrice;
    private String goodImgUrl;
    private Integer goodStore;
    private Date startTime;
    private Date endTime;

    public Integer getGoodId() 
        return goodId;
    

    public void setGoodId(Integer goodId) 
        this.goodId = goodId;
    

    public String getGoodName() 
        return goodName;
    

    public void setGoodName(String goodName) 
        this.goodName = goodName;
    

    public String getGoodNameDesc() 
        return goodNameDesc;
    

    public void setGoodNameDesc(String goodNameDesc) 
        this.goodNameDesc = goodNameDesc;
    

    public BigDecimal getGoodPrice() 
        return goodPrice;
    

    public void setGoodPrice(BigDecimal goodPrice) 
        this.goodPrice = goodPrice;
    

    public Integer getGoodStore() 
        return goodStore;
    

    public void setGoodStore(Integer goodStore) 
        this.goodStore = goodStore;
    

    public String getGoodImgUrl() 
        return goodImgUrl;
    

    public void setGoodImgUrl(String goodImgUrl) 
        this.goodImgUrl = goodImgUrl;
    

    public Date getStartTime() 
        return startTime;
    

    public void setStartTime(Date startTime) 
        this.startTime = startTime;
    

    public Date getEndTime() 
        return endTime;
    

    public void setEndTime(Date endTime) 
        this.endTime = endTime;
    

    @Override
    public String toString() 
        return "Goods" +
                "goodId=" + goodId +
                ", goodName='" + goodName + '\\'' +
                ", goodNameDesc='" + goodNameDesc + '\\'' +
                ", goodPrice=" + goodPrice +
                ", goodStore='" + goodStore + '\\'' +
                ", goodImgUrl='" + goodImgUrl + '\\'' +
                ", startTime=" + startTime +
                ", endTime=" + endTime +
                '';
    



@Mapper
public interface GoodsMapper 
    List<Goods> selectAllGoods();



@Service
public class GoodsServiceImpl implements GoodsService 

    @Autowired
    private GoodsMapper goodsMapper;

    public List<Goods> getAllGoods() 
        return goodsMapper.selectAllGoods();
    

    public Goods getGoodsById(Integer goodsId) 
        return goodsMapper.selectByPrimaryKey(goodsId);
    

    public int decrByStore(Integer goodsId, Integer buyNum) 
        return goodsMapper.updateByStore(goodsId, buyNum);
    

<?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.company.mapper.GoodsMapper">
    <resultMap id="BaseResultMap" type="com.company.model.Goods">
        <id column="good_id" jdbcType="INTEGER" property="goodId"/>
        <result column="good_name" jdbcType="VARCHAR" property="goodName"/>
        <result column="good_name_desc" jdbcType="VARCHAR" property="goodNameDesc"/>
        <result column="good_price" jdbcType="DECIMAL" property="goodPrice"/>
        <result column="good_img_url" jdbcType="VARCHAR" property="goodImgUrl"/>
        <result column="good_store" jdbcType="INTEGER" property="goodStore"/>
        <result column="start_time" jdbcType="TIMESTAMP" property="startTime"/>
        <result column="end_time" jdbcType="TIMESTAMP" property="endTime"/>
    </resultMap>
    <sql id="Base_Column_List">
        good_id, good_name, good_name_desc, good_price, good_store,good_img_url, start_time, end_time
    </sql>

    <select id="selectAllGoods" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from goods
    </select>

    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from goods
        where good_id = #goodId,jdbcType=INTEGER
    </select>

    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
        delete
        from goods
        where good_id = #goodId,jdbcType=INTEGER
    </delete>

    <insert id="insert" parameterType="com.company.model.Goods">
        insert into goods (good_id, good_name, good_price,good_store)
        values (#goodId,jdbcType=INTEGER, #goodName,jdbcType=VARCHAR, #goodPrice,jdbcType=DECIMAL,
                #goodStore,jdbcType=INTEGER)
    </insert>

    <insert id="insertSelective" parameterType="com.company.model.Goods">
        insert into goods
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="goodId != null">
                good_id,
            </if>
            <if test="goodName != null">
                good_name,
            </if>
            <if test="goodPrice != null">
                good_price,
            </if>
            <if test="goodStore != null">
                good_store,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="goodId != null">
                #goodId,jdbcType=INTEGER,
            </if>
            <if test="goodName != null">
                #goodName,jdbcType=VARCHAR,
            </if>
            <if test="goodPrice != null">
                #goodPrice,jdbcType=DECIMAL,
            </if>
            <if test="goodStore != null">
                #goodStore,jdbcType=INTEGER,
            </if>
        </trim>
    </insert>
    <update id="updateByPrimaryKeySelective" parameterType="com.company.model.Goods">
        update goods
        <set>
            <if test="goodName != null">
                good_name = #goodName,jdbcType=VARCHAR,
            </if>
            <if test="goodPrice != null">
                good_price = #goodPrice,jdbcType=DECIMAL,
            </if>
            <if test="goodStore != null">
                good_store = #goodStore,jdbcType=INTEGER,
            </if>
        </set>
        where good_id = #goodsId,jdbcType=INTEGER
    </update>
    <update id="updateByPrimaryKey" parameterType="com.company.model.Goods">
        update goods
        set good_name  = #goodName,jdbcType=VARCHAR,
            good_price = #goodPrice,jdbcType=DECIMAL,
            good_store = #goodStore,jdbcType=INTEGER
        where good_id = #goodsId,jdbcType=INTEGER
    </update>

    <update id="updateByStore">
        update goods
        set good_store = good_store - #buyNum,jdbcType=INTEGER
        where good_id = #goodsId,jdbcType=INTEGER
    </update>
</mapper>

6、创建服务提供者访问方法,基于RESTFUL风格

@RestController
public class GoodsController 

    @Autowired
    private GoodsService goodsService;
    
    @GetMapping(value = "/eureka/service/goodList")
    public List<Goods> goodList()
        List<Goods> goodsList = goodsService.getAllGoods();

        System.out.println("查询商品列表成功:");
        for (Goods good:goodsList) 
            System.out.println("查询商品:"+ good);
        
        return goodsList;
    

7、启动springboot启动类,访问应用,再去查看 Eureka 控制中心控制台服务 http://localhost:9001/eureka/service/goodList

http://localhost:8761/

3、Eureka注册服务消费者

1、新建一个springboot Module(springcloud-3-service-eureka-consumer),设置父项目 (服务消费者)

2、添加 web依赖,springcloud的common公共服务,springboot自动热部署,spring-cloud-starter-netflix-eureka-client 客户端支持

eureka 客户端的依赖!!!spring-cloud-starter-netflix-eureka-client

<!--spring-cloud-starter-netflix-eureka-client-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--继承统一的父项目-->
    <parent>
        <groupId>com.company</groupId>
        <artifactId>springcloud-demo</artifactId>
        <version>1.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.company</groupId>
    <artifactId>springcloud-3-service-eureka-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>springcloud-3-service-eureka-consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring web 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--依赖统一的springcloud-service-commons项目-->
        <dependency>
            <groupId>com.company</groupId>
            <artifactId>springcloud-2-service-common</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!-- springboot 开发自动热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

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

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、application.prperties配置文件中配置访问端口8081

server.port=8081

#设置应用名称,对应Eureka控制台下 DS Replicas 的 Application
spring.application.name=springcloud-3-service-eureka-consumer

#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
eureka.instance.lease-renewal-interval-in-seconds=30
#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
eureka.instance.lease-expiration-duration-in-seconds=60
#告诉服务端,服务实例以IP作为链接,不是取机器名
eureka.instance.prefer-ip-address=false

#注册服务实例名称
eureka.instance.instance-id=springcloud-3-service-eureka-consumer
#注册中心的链接地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

4、Springboot启动类上添加@EnableEurekaClient 注解,表明是一个 eureka 客户端,让服务消费者可以使用 eureka 注册中心

@EnableEurekaClient  //开启 Eureka client服务
@SpringBootApplication
public class Eureka3ConsumerApplication 

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

5、创建一个RestConfig配置类,创建RestTemplate;使用Ribbon调用(服务的发现由 eureka 客户端实现,而服务的消费由 Ribbon 实现)

注:

服务的发现由 eureka 客户端实现,而服务的消费由 Ribbon 实现,因此服务的调用需要 eureka 客户端和 Ribbon,两者配合起来才能实现;

Eureka 客户端是一个 Java 客户端,用来连接 Eureka 服务端,与服务端进行交互、负载均衡,服务的故障切换等;

Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡器,当使用 Ribbon 对服务进行访问的时候,它会扩展 Eureka 客户端的服务发现功能,实现从Eureka 注册中心中获取服务端列表,并通过 Eureka 客户端来确定服务端是否己经启动。

Ribbon 在 Eureka 客户端服务发现的基础上,实现了对服务实例的选择策略,从而实现对服务的负载均衡消费。

@Configuration
public class RestConfig 

    //使用Ribbon实现负载均衡的调用
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate () 
        return new RestTemplate();
    

6、创建服务消费者访问方法,基于RESTFUL风格

@RestController
public class GoodsController 
    private final String GOODS_SERVICE_URL = "http://localhost:9001/service/goodList";

    private final String GOODS_SERVICE_EUREKA_URL = "http://springcloud-3-service-eureka-provider/eureka/service/goodList";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "/springcloud/eureka/goodList")
    public @ResponseBody Object getGoodList()
        //调用远程的一个controller(Restful风格调用)
        ResponseEntity<Object> responseEntity = restTemplate.getForEntity(GOODS_SERVICE_EUREKA_URL, Object.class);

        return responseEntity.getBody();
    

7、启动springboot启动类,访问应用,测试能否正常运行 http://localhost:8081/springcloud/eureka/goodList

这时再去访问 Eureka 控制台,就会发现一个服务提供者,和一个服务消费者

以上是关于SpringCloud - Spring Cloud Netflix 之 Eureka,Ribbon的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud总结29.Zuul的FallBack回退机制

基于consul的服务注册(含踩坑过程)

Oauth2.0 整合springCloud的Zuul 解决关键BUG 报错信息:Principal must not be null

Spring Cloud Alibaba - 02 SpringCloud SpringCloud Alibaba SpringBoot的生产版本选择

Spring Cloud

spring cloud 服务注册、发现了解