Spring Cloud Eureka 概念与示例

Spring Cloud Eureka 是Spring Cloud Netflix 微服务套件中的一部分,它基于Netflix Eureka 做了二次封装,主要负责完成微服务架构中的服务治理功能。Spring Cloud通过为Eureka增加了Spring Bot风格的自动化配置。服务治理是微服务架构中最为核心和基础的模块,主要用来实现微服务实例自动化注册与发现。

  • 注册服务:就是将提供某个服务的模块信息(通常是这个服务的ip和端口)注册到1个公共的组件上
  • 服务发现:就是新注册的这个服务模块能够及时的被其他调用者发现。不管是服务新增和服务删减都能实现自动发现

1.Eureka 示例

Eureka服务器端,我们称之为注册中心,Eureka支持以集群模式部署,各个微服务启动时,会通过 Eureka Client 向 Eureka Server 注册自己,Eureka Server 会存储该服务的信息也就是说,每个微服务的客户端和服务端,都会注册到 Eureka Server

Eureka客户端:主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式嵌入在客户端应用程序的代码中。运行时,Eureka 客户端向注册中心注册自身提供的服务并周期性的发送心跳来更新它的服务租约。同时,它也能从服务端查询当前注册的服务信息并缓存到本地并周期的刷新服务状态

项目结构说明

项目模块说明

功能说明模块名端口
注册中心ereka-peer1000
注册服务ms-customer8001
消费服务ms-ribbon-consumer8002

eureka-peer 等Spring Boot应用在项目中是以模块组成springcloud项目下的pom.xm参考如下

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>

    <groupId>springcloud</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>eureka-peer</module>
        <module>ms-customer</module>
        <module>ms-ribbon-consumer</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>



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

</project>

1.1 服务注册中心

Eureka服务器端,我们称之为注册中心,Eureka支持以集群模式部署,各个微服务启动时,会通过 Eureka Client 向 Eureka Server 注册自己,Eureka Server 会存储该服务的信息

1.1.1 搭建注册中心

创建一个基础Spring Boot工程, 命名为eureka-peer, 修改pom.xml 文件,添加依赖。作为Eureka服务器端需要添加引用spring-cloud-starter-eureka-server

spring-cloud-starter-eureka-server引入了spring-cloud-netflix-eureka-server包,此包自动引入eureka-clent, 可见我们在POM里引入spring-cloud-starter-eureka-server后项目即可以当做注册中心,其也同时是客户端,可以注册自己

参考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>

    <parent>
        <groupId>springcloud</groupId>
        <artifactId>springcloud</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>eureka-peer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <!-- 服务注册中心 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.1</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

修改EurekaPeer1Application 启动信息,添加@EnableEurekaServer注解,该注解的作用为 激活Eureka中的DiscouverClient实现,创建一个InfoController 主要用于测试项目启动成功

/**
 *
 * @EnableEurekaServer注解激活Eureka中的DiscouverClient实现
 * @SpringBootApplication默认扫描CustomerApplication所在包所以需要scanBasePackages制定包名
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaPeer1Application {

    public static void main(String[] args) {
        System.out.println("服务注册中心:http://127.0.0.1:1000/");
        new SpringApplicationBuilder(EurekaPeer1Application.class).web(true).run(args);
    }
}



//InfoController.java
@RestController
public class InfoController {

    /**
     * http://127.0.0.1:1000/info/
     * @return
     */
    @RequestMapping(value = "/info", method = RequestMethod.GET)
    public String into() {

        return new Date().toString();
    }
}

修改application.properties,实现将当前应用也注册到Eureka Server

设置配置中eureka.client.register-with-eureka和eureka.client.fetch-registry参数配置为true,并设置EurekaServer地址, 实现项目启动后Eureka注册中心中自身

server.port=1000
spring.application.name=EUREKA-PEER

############ Eureka ################
#服务注册中心IP
eureka.instance.hostname=127.0.0.1
# 是否注册中心注册,默认=TRUE
eureka.client.register-with-eureka=true
# 是否检索服务
eureka.client.fetch-registry=true
#指定服务注册中心
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:1000/eureka/
############ Eureka ################

启动后控制台日志表示将EUREKA-PEER注册到服务中心

2021-10-25 08:28:19.985  INFO 6632 --- [           main] o.s.c.n.e.s.EurekaServiceRegistry        : Registering application EUREKA-PEER with eureka with status UP

访问 http://127.0.0.1:1000/ , 查看Eureka 的注服务中有一个Eureka Instance ,名称为EUREKA-PEER,如下图

1.1.2 失效剔除

Eureka Server 也就是注册中心,当注册中心启动后,各个服务将会想注册中心注册自己,Eureka Server会维护一份只读的服务清单,Eureka Server在启动的时候会创建一个定时任务,默认每隔一段时间执行 将默认清单中超时没有续约的服务剔除出去。

#Eureka Server将默认清单中超过配置时间没有续约的服务剔除
eureka.instance.lease-expiration-duration-in-seconds=90

1.1.2 不注册自己

修改eureka.client.register-with-eureka和eureka.client.fetch-registry参数配置为false的时候eureka-peer启动后就不会向eureka注册中心注册自己 ,再次访问 http://127.0.0.1:1000/  会发现Instances currentLy registered with Eureka栏是空的,没有之前的EUREKA-PEER服务


# 是否注册中心注册,默认=TRUE
eureka.client.register-with-eureka=false
# 是否检索服务
eureka.client.fetch-registry=false

1.2 服务注册

一般情况下,应用即是服务提供者也是服务消费者。例如:客户模块会使用其他已经注册的服务,同时客户模块也会向注册中心注册服务给其他模块使用

将一个Spring Boot应用注册到Eureka Server或者是从Eureka Server获取服务列表时,主要做两件事

  1. 应用启动类配置 @EnableDiscoveryClient 注解
  2. 在applicaiton.properties 中用eureka.client.serviceUrl.defaultZone参数指定服务注册中心的位置

1.2.1 搭建服务提供者

搭建完服务注册中心后,我们尝试将一个Spring Boot应用键入Eureka服务指令体系中, 创建一个ms-customer的Spring Boot项目

修改pom ,引入spring-cloud-starter-eureka

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ms-customer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 注册服务提供 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

修改Spring Boot应用代码

  1. 修改启动添加@EnableDiscoveryClient ,将应用注册未Eureka的客户端应用,激活Eureke中DiscoverClient实现,获取服务发现的能力,  
  2. 创建InfoController,实现当调用 http://127.0.0.1:8001/info/  时 返回当前服务信息
//CustomerApplication.java 参考

@EnableDiscoveryClient //将应用注册为Eureka客户端应用,激活Eureke中DiscoverClient实现,获得服务发现的能力
@SpringBootApplication(scanBasePackages = {"com.customer"})
public class CustomerApplication {

    public static void main(String[] args) {
        System.out.println("Customer:http://127.0.0.1:8001/");
        SpringApplication.run(CustomerApplication.class, args);
    }

}



//InfoController.java参考
package com.customer.controller;


import org.apache.log4j.Logger;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
public class InfoController {

    private final Logger logger = Logger.getLogger(getClass());
    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * http://127.0.0.1:8001/info/
     */
    @RequestMapping(value = "/info", method = RequestMethod.GET)
    public String into() {
        ServiceInstance instance = discoveryClient.getLocalServiceInstance();
        String message = " host:" + instance.getHost() + ",service_id:" + instance.getServiceId();
        logger.info(message);

        return  message+" Time:"+new Date().toString();
    }
}

application.properties 参考:

server.address=127.0.0.1
server.port=8001

#服务的名称
spring.application.name=MS-CUSTOMER

############ Eureka ################
#服务注册中心IP
eureka.instance.hostname=127.0.0.1
# 是否注册中心注册,默认=TRUE
eureka.client.register-with-eureka=true
# 是否检索服务
eureka.client.fetch-registry=true
#指定服务注册中心
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:1000/eureka/
#如果有两个注册中心时,参数配置多个节点
#eureka.client.serviceUrl.defaultZone=http://127.0.0.1:1111/eureka/,http://127.0.0.1:1000/eureka/

############ Eureka ################

先查看Eureka注册中心 ,打开 http://127.0.0.1:1000/  会发现MS-CUSTOMER应用已经注册到Eureka注册中心 中

应用启动后调用 http://127.0.0.1:1111/info/  查看MS-CUSTOMER应用信息

1.2.2 服务续约

上面提到过,Eureka Server会维护一个服务列表, 每隔一段时间更新列表。  当服务提供者向Eureka  Server 注册中心注册后,服务提供者也会维持一个心跳告诉Eureka  Server自己还活着,防止Eureka  Server将自己从服务列表中删除,这个过程也叫服务续约,

#服务续约 :定义服务续约任务的调用间隔时间,默认30秒
eureka.instance.lease-renewal-interval-in-seconds=30

1.2.2 服务下线

当服务实例进行正常关闭操作的时候,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心,服务端接收到请求后,会将服务状态修改Wie下线(DOWN) ,并把该下线时间传播出去。

1.3 服务发现与消费

当我们启动服务消费者的时候,他会发送一个REST请求给服务注册中心,来获取上面注册的服务清单,服务消费者获取服务清单后,通过服务名可以获得具体的提供服务的实例名和该实例的元数据信息

1.3.1 搭建服务消费者

创建ms-ribbon-consumer应用,用于模拟消费 ms-customer服务

<?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">

    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>ms-ribbon-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>


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

        <!-- 注册服务提供 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

添加注解@EnableDiscoveryClient

package com.ribbon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient //将应用注册为Eureka客户端应用,激活Eureke中DiscoverClient实现,获得服务发现的能力
@SpringBootApplication
public class RibbonConsumerApplication {

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

    @Bean
    @LoadBalanced
    RestTemplate resetTemplate(){
        return new RestTemplate();
    }

}

 创建ConsumerController 来消费服务,通过访问http://127.0.0.1:8002/ribbon-consumer 实现调用 MS-CUSTOMER服务的info信息

package com.ribbon.controller;

import org.springframework.beans.factory.annotation.Autowired;
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;

@RestController
public class ConsumerController {

    @Autowired
    RestTemplate restTemplate;

    /**
     * http://127.0.0.1:8002/ribbon-consumer
     */
    @RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)
    public String helloConsumer() {
        return restTemplate.getForEntity("http://MS-CUSTOMER/info", String.class).getBody();
    }

}

server.address=127.0.0.1
server.port=8002

#服务的名称
spring.application.name=MS-RIBBON-CONSUMER

############ Eureka ################
eureka.instance.hostname=localhost
#指定服务注册中心
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:1000/eureka/
############ Eureka ################

同时启动了三个应用,ms-customer会注册服务到服务中心, 应用ms-ribbon-consumer 可以通过服务中心调用ms-customer提供的

 http://127.0.0.1:8002/ribbon-consumer ,可见获取的结果是MS-CUSTOMER应用的info

2.Eureka 配置整理

属性

属性作用说明

eureka.instance.hostname

Eureka Serve服务实例主机名,例如localhost
eureka.instance.lease-expiration-duration-in-secondsEureka Server将超过配置时间没有续约的服务剔除,默认90秒

eureka.client.serviceUrl.defaultZon

指定服务注册中心的地址

eureka.client.register-with-eureka

是否注册中心注册,默认=TRUE

eureka.client.fetch-registry

是否需要检索服务,默认=TRUE

3.常见问题

常见启动错误

1. ClassNotFoundException

启动异常报错 
Caused by: java.lang.ClassNotFoundException: org.springframework.cloud.context.named.NamedContextFactory
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_211]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_211]
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[na:1.8.0_211]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_211]

解决方法

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

2.javax.xml.bind.JAXBContext

Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBContext
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583) ~[na:na]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
    at java.base/java.lang.Class.forName0(Native Method) ~[na:na]

从Java9开始,Java SE 的整体jar 结构都进行高度模块化,因此不会自动加载javax.xml.bind内容

增加下面的依赖

       <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.1</version>
        </dependency>

3. eureka-client报错Cannot execute request on any known server

com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
    at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:111) ~[eureka-client-1.6.2.jar:1.6.2]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.6.2.jar:1.6.2]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) ~[eureka-client-1.6.2.jar:1.6.2]

application.properties 文件中配置向注册中心注册eureka.client.register-with-eureka=true ,但是没有配置eureka.client.serviceUrl.defaultZone

项目参考:GitHub - PNZBEIJINGL/spring-cloud-lab  

前一篇:SpringCloud @RefreshScope 自动刷新Bean源码分析

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Cloud 是一个用于构建微服务架构的开源框架,它提供了一系列的解决方案和工具,帮助开发者快速构建和管理分布式系统。 以下是一个简单的 Spring Cloud 入门示例代码: 1. 创建服务注册中心(Eureka Server): ```java @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } ``` 2. 创建服务提供者(Eureka Client): ```java @SpringBootApplication @EnableDiscoveryClient public class ServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(ServiceProviderApplication.class, args); } } @RestController class HelloController { @GetMapping("/hello") public String hello() { return "Hello, Spring Cloud!"; } } ``` 3. 创建服务消费者(Eureka Client): ```java @SpringBootApplication @EnableDiscoveryClient public class ServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } } @RestController class HelloController { @Autowired private RestTemplate restTemplate; @GetMapping("/hello") public String hello() { String serviceUrl = "http://service-provider/hello"; return restTemplate.getForObject(serviceUrl, String.class); } } @Configuration class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } ``` 以上示例代码演示了使用 Spring Cloud 构建一个简单的微服务架构,其中包括服务注册中心(Eureka Server)、服务提供者(Eureka Client)和服务消费者(Eureka Client)。服务提供者注册到服务注册中心,服务消费者通过服务注册中心发现并调用服务提供者的接口。 希望以上示例能够帮助你快速入门 Spring Cloud。如果有任何问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

=PNZ=BeijingL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值