1. 程式人生 > >01.Spring Cloud Eureka服務註冊與發現

01.Spring Cloud Eureka服務註冊與發現

Spring Cloud Eureka

Spring Cloud Eureka

Spring Cloud Eureka是對Netflix Eureka的二次封裝。

  • Eureka服務端
    Eureka就是註冊中心,同時它也是一個客戶端——Eureka server(Eureka服務端)同是也是Eureka Client(Eureka客戶端)。
  • Eureka客戶端
    提供服務,向註冊中心註冊自服務,定時傳送心跳給註冊中心以更新當前服務的可用狀態。也可以從註冊中心查詢註冊的服務資訊。

1.構建服務註冊中心

新建Maven 工程,由於Spring Cloud應用是基於Spring Boot構建的,所以先匯入SpringBoot依賴:

 <parent>
      <groupId>org.springframework.boot</
groupId
>
<artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</
artifactId
>
</dependency> </dependencies>

設定Spring Milestones倉庫:

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

在**src/main下新建Spring boot啟動類:

@SpringBootApplication
public class EurekaApp {

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

}

新增spring cloud依賴:

<dependencyManagement>
    <dependencies>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
              <version>Greenwich.RC1</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
</dependencyManagement>

補充:
關於Spring Boot和Spring Cloud版本對應關係參照Spring Cloud官網:https://spring.io/projects/spring-cloud#learn
在這裡插入圖片描述

新增eureka-server依賴:

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

在啟動類上新增**@EnableEurekaServer**註解:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApp {

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

}

完整依賴:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>cloud01-eureka-server</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
    </parent>

    <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>Greenwich.RC1</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>

</project>

啟動專案:
如果有如下報錯

org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'eurekaRegistration' defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration$EurekaClientConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$EurekaClientConfiguration; factoryMethodName=eurekaRegistration; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration$EurekaClientConfiguration.class]] for bean 'eurekaRegistration': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration; factoryMethodName=eurekaRegistration; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration.class]] bound.

檢查依賴是否導錯了:

是:
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
不是:
	<artifactId>spring-cloud-netflix-eureka-server</artifactId>

如果有如下報錯:

com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect
	at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar:1.19.1]
	.....省略.....
Caused by: java.net.ConnectException: Connection refused: connect
	at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) ~[na:1.8.0_181]
	.....省略.....

2018-12-17 14:22:32.324  WARN 16608 --- [freshExecutor-0] c.n.d.s.t.d.RetryableEurekaHttpClient    : Request execution failed with message: java.net.ConnectException: Connection refused: connect
2018-12-17 14:22:32.324 ERROR 16608 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_UNKNOWN/localhost:8088 - was unable to refresh its cache! status = Cannot execute request on any known server

com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
	.....省略.....

是因為eureka-server服務端同是也是一個客戶端,也需要註冊到註冊中心去,這裡沒有指定註冊中心的位置(ip、埠等),所以會如上所示的錯誤!

解決辦法,在application.yml(application.properties)中配置:

# 開啟調示
debug: true

# 設定註冊中心埠
server:
  port: 8088
eureka:
  # 設定當前例項的資訊,一個eureka-server或者client都是一個例項
  instance:
  	# 設定主機名
    hostname: localhost
  # 註冊中心eureka-server本身也是一個客戶端 client,所以配置client連線server的屬性
  client:
    service-url:
    # 設定註冊中心的地址,${}用來讀取配置檔案中的屬性的值
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

啟動專案,訪問http://localhost:8088,即可開啟eureka server的管理介面:
在這裡插入圖片描述
UNKNOWN既是註冊的eureka client名,也就是註冊的專案的名字,可以通過spring:
application.name=EUREKA_SERVER
來修改:

# 開啟調示
debug: true



# 設定註冊中心埠
server:
  port: 8088
eureka:
  # 設定當前例項的資訊,一個eureka-server或者client都是一個例項
  instance:
    # 設定主機名
    hostname: localhost
  # 註冊中心eureka-server本身也是一個客戶端 client,所以配置client連線server的屬性
  client:
    service-url:
      # 設定註冊中心的地址,${}用來讀取配置檔案中的屬性的值
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# ----------------------------------------------
# 指定例項名
spring:
  application:
    name: EUREKA_SERVER

重啟專案,並訪問即可看到更改。

當然,如果當前專案作為註冊中心存在,可以不配置向註冊中心註冊自己,也可以解決上面的錯誤:

# 開啟調示
debug: true



# 設定註冊中心埠
server:
  port: 8088
eureka:
  # 設定當前例項的資訊,一個eureka-server或者client都是一個例項
  instance:
    # 設定主機名
    hostname: localhost
  # 註冊中心eureka-server本身也是一個客戶端 client,所以配置client連線server的屬性
  client:
    # 不向註冊中心註冊自己
    register-with-eureka: false
    # 不去發現服務(查詢服務),註冊中心提供服務註冊,不需要發現服務
    fetch-registry: false

# 指定例項名
spring:
  application:
    name: EUREKA_SERVER

2.提供服務,註冊服務

依賴

同樣的方式新建一個boot專案,在匯入eureka-server依賴的地方改成如下依賴:

 <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
</dependencies>

啟動類

新建啟動類,並在啟動類上標記**@EnableDiscoveryClient**註解:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApp {

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

}

在application.properties(application.yml)中配置資訊:

# 設定當前專案埠
server:
  port: 8089

# 設定註冊中心地址,當前client要往註冊中心註冊
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8088/eureka

# 設定當前專案的名字
spring:
  application:
    name: EUREKA_CLIENT

啟動當前專案(確保eureka-server專案已啟動),訪問eureka-server地址:http://localhost:8088,可以看到當前專案已註冊到註冊中心了:
在這裡插入圖片描述

獲取服務

新建一個controller,注入DiscoveryClient(org.springframework.cloud.client.discovery.DiscoveryClient),從DiscoveryClient中獲取服務資訊:

@RestController
public class HelloController {

    @Autowired
    private DiscoveryClient client;

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @GetMapping("/hello")
    public String hello() {
    	// 獲取服務
        List<ServiceInstance> eureka_client = client.getInstances("EUREKA_CLIENT");
        String description = client.description();
        log.info(description);
        for (ServiceInstance si : eureka_client) {
        	// 獲取每個服務對應的資訊
            String host = si.getHost();
            int port = si.getPort();
            String serviceId = si.getServiceId();
            log.info("ServiceId是:" + serviceId + " -> " + host + port);
        }
        return "hello eureka";
    }

}

訪問/hello地址,檢視控制檯列印日誌:

ServiceId是:EUREKA_CLIENT -> localhost8089

3.配置註冊中心高可用

如果系統中只有一個註冊中心,那麼這個註冊中心如果宕機了,可能會引起整個系統的癱瘓。系統的正常執行需要有高可用的註冊中心作為支撐。
這裡以maven多模組做專案演示:
新建一個maven工程作為父工程,修改packaging為pom(如果新建工程中有src/…,刪除),並修改pom檔案,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cloud</groupId>
    <artifactId>cloud01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!--引入boot專案依賴管理-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
    </parent>

    <!--引入cloud專案依賴管理-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RC1</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--一定要引入Spring Milestones,否則這個版本的依賴下載不下來,因為使用的是預覽版-->
	<repositories>
	   <repository>
	         <id>spring-milestones</id>
	         <name>Spring Milestones</name>
	         <url>https://repo.spring.io/milestone</url>
	     </repository>
	 </repositories>

</project>

在父工程下新建兩個模組,分別為cloud-eureka-server01、cloud-eureka-server02,每個工程都引入相同的依賴,並配置啟動類,啟動類上標註**@EnableEurekaServer**註解如下:

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

對兩個專案的application.properties(application.yml)分別配置:

# 這是cloud-eureka-server01的配置
# 指定專案埠(這個專案作為註冊中心,即註冊中心埠)
server:
  port: 8091

# 指定當前client註冊到的註冊中心的地址
eureka:
  client:
    service-url:
      defaultZone: http://192.168.1.35:8092/eureka/

# 設定專案名
spring:
  application:
    name: eureka_server_01
# 這是cloud-eureka-server02的配置
# 指定專案埠(這個專案作為註冊中心,即註冊中心埠)
server:
  port: 8092

# 指定當前client註冊到的註冊中心的地址
eureka:
  client:
    service-url:
      defaultZone: http://192.168.1.35:8091/eureka/

# 設定專案名
spring:
  application:
    name: eureka_server_02

啟動專案,可以發現兩個專案互相包含。
在這裡插入圖片描述

註冊服務到註冊中心叢集

新建一個maven專案cloud-eureka-client01,匯入如下依賴:

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

新建啟動類,並在啟動類上標註@EnableDiscoveryClient,並配置application.xml(application.yml):

server:
  port: 9091

eureka:
  instance:
    prefer-ip-address: true
    ip-address: 192.168.1.35

  client:
    service-url:
      defaultZone: http://192.168.35:8091/eureka/,http://192.168.1.35:8092/eureka/

spring:
  application:
    name: eureka_client01

啟動專案,訪問註冊中心地址:
在這裡插入圖片描述

3.服務的發現與消費

分別建立四個工程,如下圖所示:
在這裡插入圖片描述
其中server01,server02作為註冊中心,client01,client02作為客戶端。分別配置好各自的關係,為client01提供一個/hello請求:

@RestController
public class HelloController {
	
	@GetMapping("/hello")
	public String getHello() {
		return "Hello World!";
	}
	
}

在client02中呼叫這個服務:

@SpringBootApplication
@EnableDiscoveryClient
public class EurekaClient02App {

	@Bean
	@LoadBalanced // 開啟客戶端負載均衡
	public RestTemplate restTempalte(