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 端点。
添加依赖
- Spring Boot 项目,添加 eureka-server 依赖包,如下
| 1 | <properties> | 
  查看 Eureka Server 的依赖包,可知页面展示的端点监控信息实际是依赖于 spring-boot-starter-actuator 实现,UI页面采用的是 freemarker 模板。
  所以如果项目中已经使用了 Thymeleaf 模板,Eureka Server 的 freemarker 模板就会无法正确加载,这样就有必要手动配置模板的加载:
| 1 | spring: | 
配置运行
- 在启动类上添加开启 Eureka Server 的注解 @EnableEurekaServer。 - 1 
 2
 3
 4
 5
 6
 7
 public class EurekaServerApplication {
 public static void main(String[] args) {
 SpringApplication.run(EurekaServerApplication.class, args);
 }
 }
- 在 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,否则应用在启动时会把自己当作客户端向自己注册,会报错。 
- 直接运行 EurekaServerApplication 即可启动注册中心服务(Eureka Server)了。 
- 在浏览器直接输入 http://localhost:8761/ 即可访问 Eureka 提供的 Web 控制台。 
Eureka Clients
Eureka Client 客户端应用是服务提供者,需要注册到注册中心,供服务发现。创建一个 Eureka Client 作为服务提供者,编写接口并提供服务。
添加依赖
| 1 | <properties> | 
配置运行
- 在 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/
- 创建 Controller,编写接口 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 public class HomeController {
 
 
 public String home(){
 return "Hello World";
 }
 }
- 运行应用 - 访问接口:http://localhost:8081/sakila/home 返回:Hello World,表示的接口成功。 
- 刷新 Eureka Server 的 Web 控制台,在当前注册实例列表可以看到该客户端应用,表示注册成功。 
- 配置说明 - **defaultZone:**是个后备配置,为任何没有指定首选项的客户端提供服务 URL,可简单理解为配置默认 URL。 
消费服务接口
同样创建一个 Eureka Client 客户端应用,注册到 Eureka Server 注册中心,作为服务的消费者,来调用注册到 Eureka Server 的实例的服务接口。
- 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
- 配置注册 RestTemplate Bean - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19- /** 
 * RestTemplate配置类
 */
 public class RestTemplateConfig {
 
 public RestTemplate restTemplateOne() {
 //设置超时时间,毫秒
 return new RestTemplateBuilder().setConnectTimeout(Duration.ofMillis(1000)).setReadTimeout(Duration.ofMillis(1000)).build();
 }
 
 
 public RestTemplate restTemplateTwo(){
 //设置超时时间,毫秒
 return new RestTemplateBuilder().setConnectTimeout(Duration.ofMillis(1000)).setReadTimeout(Duration.ofMillis(1000)).build();
 }
 }
- 编写 Controller 调用服务接口 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 public class ConsumerController {
 
 private RestTemplate restTemplateOne;
 
 private RestTemplate restTemplateTwo;
 
 
 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;
 }
 }
- 浏览器访问服务消费者应用的接口,可以看到调用了服务提供者的接口,并返回正确信息。 
注意:通过 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地址的映射,客户端可以从本地缓存的注册表直接找到目的服务器)。
更多详细配置,可参考EurekaInstanceConfigBean、EurekaClientConfigBean。
若要禁用 Eureka Discovery Client, 将 eureka.client.enabled 设置为 false, 或设置 spring.cloud.discovery.enabled 为 false 也可禁用客户端服务发现。
Eureka 安全认证
Eureka Server 提供的 Web 控制台默认是没有安全认证的,在公网上是不安全的。通过集成 Spring Security 来进行安全认证。
- Eureka Server 注册中心应用引入 Spring-Secruity 依赖 - 1 
 2
 3
 4- <dependency> 
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
- Eureka Server 注册中心应用的配置文件 application.properties 添加安全认证的账号密码 - 1 
 2
 3- #认证账号密码 
 spring.security.user.name=admin
 spring.security.user.password=123456
- 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配置类
 **/
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
 protected void configure(HttpSecurity httpSecurity) throws Exception {
 httpSecurity.csrf().disable()
 .authorizeRequests().anyRequest().authenticated()
 .and().formLogin()
 .and().httpBasic();
 // super.configure(httpSecurity);
 }
 }- 再次访问 http://localhost:8761/ ,浏览器会显示登录页面,要求输入账号密码。 
- 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
其它参考
Spring Cloud(二):服务发现之Eureka注册中心(1)-服务、客户端、安全认证
http://blog.gxitsky.com/2019/02/14/SpringCloud-02-service-discover-eureka-1/

