註冊服務實例


在完成〈服務註冊伺服器〉的設置之後,接著來試著修改〈@RepositoryRestResource〉中的專案,令其能向伺服器註冊,基本上,需要有以下的相依:

implementation('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')

不過〈分離 gossip 組態〉中談過,在撰寫本文的這個時間點上,mavenCentral 中沒有 Spring Cloud 的相關相依程式庫,如果是基於〈@RepositoryRestResource〉中的專案修改,你必須增加 repositories 等額外資訊,不然會抓不到相關 JAR 檔案。例如:

...略

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/milestone" }
}

ext['springCloudVersion'] = 'Greenwich.RC2'

dependencies {
    ...略

    implementation('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')     
    ...略
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

接著,可以在 bootstrap.properties 中設定服務註冊伺服器的資訊:

server.port=8762
spring.application.name=msg-service
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
#eureka.instance.preferIpAddress=true

spring.application.name 會是這個服務註冊時使用之名稱,如果有多個服務註冊伺服器,eureka.client.serviceUrl.defaultZone 的設定中可以用逗號區隔,接著就可以啟動專案了,你可以在 Eureka 資訊頁面上看到有實例註冊了:

註冊服務實例

在資訊頁面上,可以看到服務的實體位置,目前使用主機名稱,然而,在實際上線之後,通常會使用 IP 位址,這時可以設定 eureka.instance.preferIpAddress=true

你可以試著啟動多個實例,同一名稱下就會有多個服務的實體位置資訊:

註冊服務實例

若想查找出伺服器上同一服務的全部實例,可以透過 DiscoveryClient,在標註了 @EnableDiscoveryClient 的情況下,就可以透過自動綁定來取得,例如:

...略
@RunWith(SpringRunner.class)
@EnableDiscoveryClient
@SpringBootTest
public class RestTmplApplicationTests {
    @Autowired
    private DiscoveryClient client;

    private String serviceUri;

    @Before
    public void setUp() {
        serviceUri = client.getInstances("msg-service").get(0).getUri().toString();
    }

    ...略

透過 DiscoveryClientgetInstances,可以取得 List<ServiceInstance> 實例,就目前來說,會取得兩個服務實例,每次呼叫就會向伺服器查找一次,因此實際上並不直接使用 DiscoveryClient,因為這沒有運用到本地快取的註冊表,而且 Spring 還有其他更便捷的方式來查找服務並自動負載平衡。

(如果你沒有要查找服務實例,可以將 eureka.client.fetchRegistry 設為 false,這樣就不會維謢本地的註冊表。)

在上面的 setUp 方法中,取得註冊表中第一個服務實例之 URI,因此就可以提供給 RestTemplate 使用,例如:

private RestTemplate restTemplate = restTemplate();

@Test
public void show() {
    RequestEntity<Void> request = RequestEntity
            .get(URI.create(String.format("%s/messages/%s", serviceUri, "1")))
            .build();

     ResponseEntity<Resource<Message>> response = 
             restTemplate.exchange(request, new ParameterizedTypeReference<Resource<Message>>(){});

    assertNotNull(response.getBody().getContent());
}

你可以在 DataREST 找到以上的範例專案。