基于Spring Cloud和Netflix Discovery的微服务开发


今天,我将为大家展示如何使用Eureka发现服务器(Discovery Server)来搭建一个小型的微服务应用。

我将使用Eureka作为发现服务器,各个应用可以通过Eureka来发现彼此,建立连接。

对于本例,总共将创建4个微服务应用程序。
  1. discovery-service - Eureka发现服务器
  2. library-service - 一个微服务应用程序,同时也是发现客户端(a discovery client)
  3. book-service - 一个微服务应用程序,同时也是发现客户端
  4. read-service - 一个微服务应用程序,它将同时使用book-servicelibrary-service。同时也是发现客户端,它将在发现服务器中注册自己。


发现服务器将扮演这样一个角色,所有的微服务应用程序将自己的信息注册到发现服务器,所有的微服务应用程序也可以访问这个发现服务器,以获得其他微服务应用程序的信息。当一个微服务应用程序想访问另一个微服务应用程序时,它不必提前获悉对方的主机地址和端口号,它都可以通过询问发现服务器来获得,这样的话,即使对方应用程序的地址发生了改变,也不会造成影响。

当一个应用程序从一台物理服务器迁移到另一台新的物理服务器时,我们可以从发现服务器知道新的主机地址和端口。假设你决定将应用程序从印度服务器(http://myservice.gov.in:9001)迁移到美国服务器(http://myservice.gov.us:99013),你不需要通知之前使用你服务的任何应用程序。他们可以从发现服务器自动知道新的主机地址和端口号,甚至不需要做任何事情。

请参见下图以了解发现服务器是如何工作的,如何为注册的发现客户端提供服务。例如,read-service需要使用book-servicelibrary-service提供的服务,那么read-service如何获得对方的主机名和端口号呢?这些信息将由discovery-service提供,因为book-servicelibrary-service已经将信息注册到了discovery-service中。
1.png

要了解更多关于Spring Cloud Netflix的信息,可以访问https://cloud.spring.io/spring ... .html

下面,让我们一步一步地开发这个项目。

步骤1

首先,我们将创建一个基于Eureka的discovery-service。如果你是Spring Boot的新手,可以阅读我的文章https://github.com/prateekpara ... rest2来创建一个Spring Boot应用程序。现在,请点击https://start.spring.io/打开Spring Initializr。现在请按照下方截图操作。
2.png

单击ADD DEPENDENCIES按钮并选择需要的依赖项(在搜索栏中只需键入依赖项——Eureka和Actuator即可完成添加。不要选错了,不要选择Eureka client)。
3.png

现在单击GENERATE按钮生成项目,并将其保存到你的机器上,作为Maven项目导入到你的工具中(这里我使用的是Eclipse)。
4.png

现在,打开DemoDiscoveryServerApplication.java,并添加@EnableEurekaServer
package com.bhaiti.jorhat.demodiscoveryserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableEurekaServer
public class DemoDiscoveryServerApplication {
public static void main(String[] args) {
    SpringApplication.run(DemoDiscoveryServerApplication.class, args);
}


application.properties重命名为application.yml,并添加如下信息:
server.port: 9001
spring.application.name: demo-discovery-server
eureka:
server:
evictionIntervalTimerInMs: 3000
response-cache-update-interval-ms: 3000
client:
registerWithEureka: false
fetchRegistry: false
service-url.defaultZone: http://localhost:${server.port}/eureka

从上面的配置信息中,可以看到,registerWithEurekafetchRegistry的值都是false。原因是我们不希望注册这个应用程序本身,因为此应用程序将作为发现服务器,接收其他应用程序的注册。有关配置的详细信息,请参考repository

你的发现服务器已经准备好了。

在项目主目录中,执行以下命令编译应用程序:
mvn clean package

启动应用程序:
java -jar target/demo-discovery-server-0.0.1-SNAPSHOT.jar

现在你可以通过仪表板来查看Eureka发现服务器,请点击 http://localhost:9001
5.png

现在你还看不到任何Eureka客户端应用程序。让我们开发我们的第一个Eureka客户端应用程序book-service

步骤2

按以下步骤创建一个REST应用程序book-service
6.png

请注意,这次我们选择了Eureka Client作为依赖项 ,因为我们的REST应用程序也是Eureka客户端应用程序。生成项目并将其作为Maven项目导入到Eclipse中。

application.properties重命名为application.yml,并添加如下配置:
server.port: 9901
spring:
application.name: book-service 
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9001/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1

通过配置项defaultZone可以看到,这个Eureka客户端应用程序将自己注册到http://localhost:9001/eureka/这个地址。现在我们必须在REST应用程序book-service中进行一些编码。首先打开BookServiceApplication.java文件,并在其中添加@EnableDiscoveryClient以激活发现客户机。
package com.bhaiti.jorhat.book.bookservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class BookServiceApplication {

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


按如下所示,创建一个新的Java类BookService.java
7.png

并添加如下代码:
package com.bhaiti.jorhat.book.bookservice;

import java.util.Arrays;
import java.util.List;

public class BookService {  

private static List<String> bookList = Arrays.asList("Book1","Book2","Book3");

public static List<String> getBookList() {
    return bookList;
}


同样的方法,创建BookController.java
package com.bhaiti.jorhat.book.bookservice;

import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BookController {

@GetMapping("/books")
public ResponseEntity<List<String>> getBookList(){ 
    return ResponseEntity.ok(BookService.getBookList());    
}


pom.xml中添加如下依赖项:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId> 
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

现在,我们可以编译并且运行它了:
cd book-service
mvn clean package
java -jar target/book-service-0.0.1-SNAPSHOT.jar

现在刷新Eureka(发现服务器)仪表板,你可以看到book-service已经被注册进来了。
8.png

步骤3

现在创建library-service应用程序。只需重复步骤2,创建项目并将其导入到Eclipse中。
9.png

参考book-service更新library-servicepom .xml。分别添加两个类LibraryService.javaLibraryController.java

首先修改LibraryServiceApplication.java,添加@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class LibraryServiceApplication {
public static void main(String[] args) {
    SpringApplication.run(LibraryServiceApplication.class, args);
}


按如下方式创建LibraryService.java
package com.bhaiti.uk.global.repo;

import java.util.HashMap;
import java.util.Map;
public class LibraryService {

private static Map<String, String> libList;

static {
    libList = new HashMap<String, String>();
    libList.put("Book1", "Library3");
    libList.put("Book2", "Library1");
    libList.put("Book3", "Library2");
}

public static Map<String, String> getLibList() {
    return libList;
}


按如下方式创建LibraryController.java
package com.bhaiti.uk.global.repo;

import java.util.Map;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LibraryController {

   @GetMapping("/librarys")
   public ResponseEntity<Map<String, String>> getBookList(){ 
          return ResponseEntity.ok(LibraryService.getLibList()); 
   }


application.properties重命名为application.yml,并添加如下配置:
server.port: 9902
spring:
application.name: library-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9001/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1

编译并且运行应用程序:
cd library-service
mvn clean package
java -jar target/library-service-0.0.1-SNAPSHOT.jar

现在刷新Eureka(发现服务器)仪表板,你可以看到library-service已经被注册进来了。
10.png

步骤5

现在我们将创建最后一个REST应用程序——read-service。创建并将其导入到Eclipse中。请注意,我们在这里增加了一个依赖项,即OpenFeign。
11.png

application.properties重命名为application.yml,并添加如下配置:
server.port: 9903
spring:
application.name: library-service 
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:9001/eureka}
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1

参照library-service修改pom.xml

read-service中,我们将同时使用book-servicelibrary-service。为了调用book-servicelibrary-service的REST API,我们将在这里实现一个假想客户机。

首先修改ReadServiceApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class ReadServiceApplication { 

现在,创建我们的Feign客户端。分别创建两个接口BookClient.javaLibraryClient
package com.bhaiti.jorhat.read;

import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient("book-service")
public interface BookClient {

@GetMapping("/books")
List<String> getBookList(); 


package com.bhaiti.jorhat.read;

import java.util.Map;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient("library-service")
public interface LibraryClient {

@GetMapping("/librarys")
Map<String, String> getLibraryList();


使用FeignClient的好处是,当进行REST调用时,你不需要知道对方的主机名和端口号。在这里,我们没有使用URI来对book-service进行REST调用。Feign可以获取REST调用所需的一切,从discovery server获取关于book-servicelibrary-service的一切信息(主机名和端口号)。因为book-servicelibrary-service不仅是基于REST的应用程序,也是Eureka客户端应用程序,因此它可以从发现服务器中获取的其他Eureka客户端应用程序的信息。

要了解更多关于FeignClient的信息,请访问https://cloud.spring.io/spring ... .htmlhttps://cloud.spring.io/spring ... html/

假设你不想使用FeignClient,而想使用http连接或RestTemplate进行REST调用,在这种情况下,你可以使用以下代码获取应用程序的主机名和端口号。
@Autowired
private EurekaClient eurekaClient;

public String getBaseUrl() {
Application application = eurekaClient.getApplication("book-service");
InstanceInfo instanceInfo = application.getInstances().get(0);
String hostname = instanceInfo.getHostName();
int port = instanceInfo.getPort();
return "http://" + hostname + ":" + port;


按如下方式创建ReadServiceController.java
package com.bhaiti.jorhat.read;

import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ReadServiceController {

@Autowired
BookClient bookClient;
@Autowired
LibraryClient libraryClient;

@GetMapping(path= "/read/{bookName}", produces = "application/json")

public ResponseEntity<String> getReadingLocation(@PathVariable(value = "bookName") String bookName){

    String response;
    List<String> bookList = bookClient.getBookList(); 
    if(bookList.contains(bookName)) {
        Map<String, String> libList = libraryClient.getLibraryList();
        response = "You can read this book - " + bookName 
                + " at this Library - " + libList.get(bookName);
    } else {
        response = "Your Book - " + bookName + " is not currently available in Libaries";
    }
    return ResponseEntity.ok().body(response);  
}


最后,按如下方式修改ReadServiceApplication.java
package com.bhaiti.jorhat.read;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class ReadServiceApplication {
public static void main(String[] args) {
    SpringApplication.run(ReadServiceApplication.class, args);
}


现在,你的微服务应用程序已经完全准备好进行测试了。

首先编译并运行它,然后检查Eureka服务器。
cd read-service
mvn clean package
java -jar target/read-service-0.0.1-SNAPSHOT.jar

12.png

现在,点击下面的URL并检查。
13.png

你将在浏览器中看到如下信息。
14.png

只需将书名更改为Book1、Book2和Book4,并对每个条目进行测试。你可以通过以下链接获得所有源代码:https://github.com/prateekpara ... ample

希望你喜欢本教程。

原文链接:How to Develop Microservices With Spring Cloud and Netflix Discovery(翻译:钟涛)

3 个评论

微服务是一种理念,不是具体的技术
然后呢?
然后呢?

要回复文章请先登录注册