Spring Cloud(二):服务发现之Eureka注册中心(1)-服务、客户端、安全认证

  在学习 Eureka 之前,先了解下 Spring Cloud Netflix
  
  Spring Cloud Netflix 通过自动配置和绑定 Spring 环境以及 Spring 编程模型习惯为 Spring Boot 应用程序提供 Netflix OSS 集成。通过一些简单的注释,即可快速启用和配置常见的组件,并使用经过实战考验的 Netflix 组件构建大型分布式系统,提供的组件包含服务发布(Eureka)、断路器(Hystrix)、智能路由(Zuul)、客户端负载均衡

  Spring Cloud Eureka 是 Spring Cloud Netflix 套件之一;是 Netflix 服务发现服务器和客户端,主要负责服务发现;是一个基于 REST 的服务,能够方便地将服务注册到 Eureka 中进行统一管理,配置和部署高可用服务器,每个服务器将注册服务的状态复制到其他服务器(管理所有服务的信息和状态)。

  Spring Cloud Netflix 项目地址Spring Cloud Netflix 文档

Eureka 注册中心(服务发现)包含**服务器(Server)客户端(Client)**两部份。

Eureka Server

Service Discovery: Eureka Server,注册中心服务给服务提供者注册, 服务端提供了一个主页,其中包含了位于**/eureka/* **下常规的 eureka 功能的 UI 和 HTTP API 端点。

添加依赖

  1. Spring Boot 项目,添加 eureka-server 依赖包,如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </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>

    <repositories>
    <repository>
    <id>spring-milestones</id>
    <name>Spring Milestones</name>
    <url>https://repo.spring.io/milestone</url>
    </repository>
    </repositories>

查看 Eureka Server 的依赖包,可知页面展示的端点监控信息实际是依赖于 spring-boot-starter-actuator 实现,UI页面采用的是 freemarker 模板。
所以如果项目中已经使用了 Thymeleaf 模板,Eureka Server 的 freemarker 模板就会无法正确加载,这样就有必要手动配置模板的加载:

1
2
3
4
spring:
freemarker:
template-loader-path: classpath:/templates/
prefer-file-system-access: false

配置运行

  1. 在启动类上添加开启 Eureka Server 的注解 @EnableEurekaServer

    1
    2
    3
    4
    5
    6
    7
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
    public static void main(String[] args) {
    SpringApplication.run(EurekaServerApplication.class, args);
    }
    }
  2. application.properties 配置文件添加如下配置。

    1
    2
    3
    4
    5
    6
    7
    8
    #定义应用名(服务名)
    spring.application.name=eureka-server
    server.port=8761
    eureka.instance.hostname=localhost
    #因自己就是注册中心,所以关闭向注册中心注册自己
    eureka.client.register-with-eureka=false
    #因注册中心的职责是维护实例,并不需要去检索服务,所以关闭
    eureka.client.fetch-registry=false

    eureka.client.register-with-eureka 一定要配置为 false,否则应用在启动时会把自己当作客户端向自己注册,会报错。

  3. 直接运行 EurekaServerApplication 即可启动注册中心服务(Eureka Server)了。

  4. 在浏览器直接输入 http://localhost:8761/ 即可访问 Eureka 提供的 Web 控制台。

Eureka Clients

Eureka Client 客户端应用是服务提供者,需要注册到注册中心,供服务发现。创建一个 Eureka Client 作为服务提供者,编写接口并提供服务。

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</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>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

配置运行

  1. application.properties 配置文件添加如下配置

    1
    2
    3
    4
    5
    6
    #端口
    server.port=8081
    #定义应用名(服务名)
    spring.application.name=sakila-service
    #eureka 注册中心地址
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
  2. 创建 Controller,编写接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @RestController
    @RequestMapping("/sakila")
    public class HomeController {

    @GetMapping("/home")
    public String home(){
    return "Hello World";
    }
    }
  3. 运行应用

    访问接口:http://localhost:8081/sakila/home 返回:Hello World,表示的接口成功。

  4. 刷新 Eureka Server 的 Web 控制台,在当前注册实例列表可以看到该客户端应用,表示注册成功。

  5. 配置说明

    defaultZone:是个后备配置,为任何没有指定首选项的客户端提供服务 URL,可简单理解为配置默认 URL。

消费服务接口

同样创建一个 Eureka Client 客户端应用,注册到 Eureka Server 注册中心,作为服务的消费者,来调用注册到 Eureka Server 的实例的服务接口。

  1. application.properties 配置

    1
    2
    3
    4
    5
    6
    #端口
    server.port=8082
    #定义应用名(服务名)
    spring.application.name=sakila-consumer
    #eureka 注册中心地址
    eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka
  2. 配置注册 RestTemplate Bean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**
    * RestTemplate配置类
    */
    @Configuration
    public class RestTemplateConfig {

    @Bean(name = "restTemplateOne")
    public RestTemplate restTemplateOne() {
    //设置超时时间,毫秒
    return new RestTemplateBuilder().setConnectTimeout(Duration.ofMillis(1000)).setReadTimeout(Duration.ofMillis(1000)).build();
    }

    @Bean(name = "restTemplateTwo")
    @LoadBalanced
    public RestTemplate restTemplateTwo(){
    //设置超时时间,毫秒
    return new RestTemplateBuilder().setConnectTimeout(Duration.ofMillis(1000)).setReadTimeout(Duration.ofMillis(1000)).build();
    }
    }
  3. 编写 Controller 调用服务接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @RestController
    @RequestMapping("/consumer")
    public class ConsumerController {

    @Autowired
    private RestTemplate restTemplateOne;
    @Autowired
    private RestTemplate restTemplateTwo;

    @GetMapping("/callHello")
    public String callHello() {

    //直接调用服务接口
    String url1 = "http://localhost:8081/sakila/home";

    //通过Eureka来调用服务接口
    String url2 = "http://sakila-service/sakila/home";

    String str1 = restTemplateOne.getForObject(url1, String.class);
    String str2 = restTemplateTwo.getForObject(url2, String.class);
    return str1 + "---" + str2;
    }
    }
  4. 浏览器访问服务消费者应用的接口,可以看到调用了服务提供者的接口,并返回正确信息。

注意:通过 Eureka 来调用其它服务,是根据 spring.application.name 属性定义的应用名(也称为服务名 或 服务ID(serviceId))来获取服务的,而不是 eureka.instance.appname 定义的实例名。

Eureka 更多描述

当项目中引入了 spring-cloud-starter-netflix-eureka-client 依赖包,应用会从配置文件中找到注册中心的 URL 地址作为 Eureka Client 自动注册到 Eureka Server。

当 Eureka Client 向 Eureka Server 注册时,Client 会提供有关自身的元数据信息,如主机地址、端口、健康指示器URL、主页和其他详信息。

Eureka Server 接收每个客户端实例发送的心跳信息以保持最新状态,如果心跳超时,通常会从注册表中删除该实例。

默认应用名称(服务名)、虚拟主机端口分别取值环境变量 ${spring.application.name}${spring.application.name}${server.port}

Eureka Client 客户端实例的行为由 eureka.instance.* 配置键驱动,如果应用程序配置了 spring.application.name(这是 Eureka 服务ID 或 优先默认值),则默认值更好。

Eureka Client 客户端会缓存一个 Eureka Server 实例注册表,也就是说,客户端不必为服务的每个请求转到注册中心(注册表包含了实例名和实例URL地址的映射,客户端可以从本地缓存的注册表直接找到目的服务器)。

更多详细配置,可参考EurekaInstanceConfigBeanEurekaClientConfigBean

若要禁用 Eureka Discovery Client, 将 eureka.client.enabled 设置为 false, 或设置 spring.cloud.discovery.enabledfalse 也可禁用客户端服务发现。

Eureka 安全认证

Eureka Server 提供的 Web 控制台默认是没有安全认证的,在公网上是不安全的。通过集成 Spring Security 来进行安全认证。

  1. Eureka Server 注册中心应用引入 Spring-Secruity 依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
  2. Eureka Server 注册中心应用的配置文件 application.properties 添加安全认证的账号密码

    1
    2
    3
    #认证账号密码
    spring.security.user.name=admin
    spring.security.user.password=123456
  3. Eureka Server 注册中心应用新增 Spring Secruity 配置类

    禁用 CSRF 安全防护,否则客户端无法注册并报错。开启对所有请求要求输入账号密码进行认证。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @name: SpringSecurityConfig
    * @desc: SpringSecurity配置类
    **/
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity.csrf().disable()
    .authorizeRequests().anyRequest().authenticated()
    .and().formLogin()
    .and().httpBasic();
    // super.configure(httpSecurity);
    }
    }

    再次访问 http://localhost:8761/ ,浏览器会显示登录页面,要求输入账号密码。

  4. Eureka Client 客户端只需在配置文件 application.properties 文件的注册中心地址配置的 URL 加上账号密码即可。
    URL样式:http://user:password@localhost:8761/eureka

    1
    2
    #eureka 注册中心地址
    eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka

其它参考

  1. SpringCloud教程 | 二.Eureka常见问题总结

Spring Cloud(二):服务发现之Eureka注册中心(1)-服务、客户端、安全认证

http://blog.gxitsky.com/2019/02/14/SpringCloud-02-service-discover-eureka-1/

作者

光星

发布于

2019-02-14

更新于

2022-06-17

许可协议

评论