一光年

[SpringCloud-极简示例] 3. 加入Eureka,实现服务注册与发现

2019.06.20

示例2中虽然实现了两个微服务之间的Http通信,但是有一个明显的不足:两个服务之间的通信地址是通过硬编码实现的。加入Provider的IP地址修改了,那么Consumer的代码也要做相应的修改,这种强耦合是不被允许的。

关于解决方法,可以考虑将Provider的IP地址写入配置文件中,通过修改配置就可以切换不同的服务,解决了代码耦合的问题。

但是在微服务的语境下,光凭配置文件恐怕很难应对实际情况。

想象一下,一个系统包含数十个上百个微服务,如果一个Consumer只同一个Provider通信还好,如果是需要调用数十个Provider的服务,那配置文件就相当复杂了。如果Provider更改了自己的部署地址,那配置文件也必须同时修改。

所以在微服务中,服务的发现和注册是重要的支撑功能。它可以让Consumer在仅仅知道Provider名称的情况下,就可以调用它的服务,而无需考虑部署IP等信息。

本例中,我们将加入Eureka模块,帮助实现服务的注册与发现功能。 demo2-eureka-2

Eureka服务启动

在Spring Initializr中生成Eureka项目,项目需导入Eureka Server包的依赖。

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

在项目的主程序中加入@EnableEurekaServer标注即可开启服务。

package com.example.springcloud.wseureka;
...

@SpringBootApplication
@EnableEurekaServer
public class WsEurekaApplication {

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

在application.yml配置中,加入以下设定:


server:
  port: 8765
eureka:
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://localhost:8765/eureka/

打开浏览器,输入网址 http://localhost:8765/,打开以下网页,可以看到当前没有服务被发现和注册。 demo2-eureka-1

将Provider和Consumer注册到Eureka

要将一个SpringBoot服务注册到Eureka,仅需引入EurekaClient依赖即可,在pom.xml中添加以下依赖。

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

另外在配置文件中,加入以下设定:

server:
  port: 8081

spring:
  application:
    name: ms-provider   // 声明服务的名称
    
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8765/eureka/
  instance:
    prefer-ip-address: true

Provider服务和Consumer服务都是同样的配置,不同的是要设置不同的application服务名字。

重启Provider和Consumer后,可以看到Eureka的管理界面中,已经加入了MS-PROVIDER和MS—CONSUMER。 demo2-eureka-3

Consumer使用EurekaAPI访问Provider

在示例1中,Consumer使用IP地址直接访问的Provider服务。加入Eureka后,Consumer可以通过Provider名获取对应服务内置内容,包括URL地址。

package com.example.springcloud.comsumer.web;
...

@RestController
@RequestMapping("")
public class DemoController {
	
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/product/{id}")
    public Object getProvider(@PathVariable Integer id) throws MalformedURLException {
		
        List<ServiceInstance> services = discoveryClient.getInstances("ms-provider");
        if (services.size() > 0) {
            String URL = services.get(0).getUri().toURL().toString();
            return restTemplate.getForObject(URL + "/" + id, Object.class);
        }
        return "找不到服务";
    }
}

重启Provider和Consumer,访问地址 http://localhost:8080/product/1,即可看到以下返回值:

{"id":1,"name":"Name-1"}

小结

Eureka服务的主要目的,是为其它微服务提供服务查询和注册功能,相当于黄页地址的作用。有了这个黄页,微服务只需向Eureka注册便可已服务名的方式,向其它微服务提供数据接口服务。