SpringCloud搭建基於Eureka服務中心的微服務體系
一、單體系統與微服務體系
在以往傳統的企業系統架構中,所有的業務介面都被集中在同個單體應用中。在業務需求不龐大的情況下,這樣的系統架構在開發、測試、部署時都還比較方便,但是隨著企業的發展,更多的業務需求也隨之而來,單體應用為了滿足這些需求就必須增加相應的業務模組,單體應用就會顯得越來越臃腫;由於單體應用的所有業務都執行在同一個系統程序中,即使我們只是修改了一個很小的功能,也需要將整個專案全量更新上線,進而導致影響其他功能;單體應用的架構和業務邏輯對所有參與的開發者都是開放的,這就帶來了一定的風險,某個開發者的一個誤操作就有可能影響整個系統。
基於以上幾點,分散式的微服務體系應運而生,它將系統內的各個功能模組拆分成不同的服務,這些服務都可以獨立部署和擴充套件;由於各服務都執行在各自的程序中,每個服務的更新或是中斷都不會影響其他服務;不同的業務可以根據不同的需求去自定義技術平臺、伺服器配置、資料庫配置等,從而避免出現“殺雞用牛刀”等情況;開發者只需根據業務劃分,維護自己負責的服務,降低了開發風險。
二、SpringCloud簡介
SpringCloud是一個基於SpringBoot的微服務架構開發工具。他提供了微服務開發所需的配置管理、服務發現、斷路器、智慧路由、微代理、控制匯流排、全域性鎖、決策競選、分散式會話和叢集狀態管理等元件。最重要的是,跟spring boot框架一起使用的話,會讓你開發微服務架構的雲服務非常好的方便。SpringBoot旨在簡化建立產品級的 Spring 應用和服務,簡化了配置檔案,使用嵌入式web伺服器,含有諸多開箱即用微服務功能。
三、核心結構分析
整個微服務體系主要由三個核心模組組成:Eureka服務註冊中心、服務提供者、服務消費者。
Eureka服務註冊中心:Eureka提供的服務端,用於註冊、發現、
他們的邏輯關係如下圖所示,稍後會結合具體實現,進行分析。
四、具體實現
1、建立Eureka服務註冊中心:
1.1 建立SpringBoot工程
以idea為例,建立一個SpringBoot工程,在選擇依賴的時候,在Cloud Discovery下找到EureKa Server並勾選,這樣選擇之後,idea就會幫助我們補充好pom中需要的依賴,其他一路next即可;
1.2 配置application.properties:
server.port:服務監聽的埠
eureka.instance.hostname:eureka例項的主機名稱;
eureka.client.register-with-eureka:是否將本專案作為服務註冊到服務中心,由於本專案就是服務中心,所以就設定為false;
eureka.client.fetch-registry:是否需要檢索服務,這裡也不需要;
eureka.client.service-url.defaultZone:eureka服務中心的訪問地址;
spring.application.name:eureka服務中心的應用名稱;
server.port=1112
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
spring.application.name=eureka_server
1.3 設定Application,開啟EurekaServer:
package com.eureka_center;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaCenterApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaCenterApplication.class, args);
}
}
設定完成後,執行專案,看到如下介面證明執行成功:
2、建立並註冊服務提供者:
2.1 建立一個Spring Boot應用
可以直接通過IDE建立,也可以進入https://start.spring.io/進行建立;
2.2 配置pom.xml
pom.xml:
<?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.service_provider</groupId>
<artifactId>service_provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>service_provider</name>
<description>service_provider for Spring Cloud</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<!--全棧web開發模組,包含嵌入式Tomcat、SpringMVC-->
<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>
<scope>test</scope>
</dependency>
<!--Eureka服務端依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
</dependencies>
<!--Spring Cloud 依賴-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
這裡有一點要注意,就是SpringCloud的版本要與springboot相對應,我這裡使用的SpringBoot的版本是2.0.5.RELEASE對應的SpringCloud版本是Finchley.SR1。(可以直接套用之前配置eureka服務中心的SpringCloud)
2.3 配置application.properties:
server.port=9001
spring.application.name=hello-service
eureka.client.service-url.defaultZone=http://localhost:1112/eureka/
2.4 新建一個RestController
DiscoveryClinet用於幫助客戶端與eureka server互相協作:
1、向server註冊服務例項;
2、向server服務租約;
3、服務關閉期間,向server取消租約;
4、查詢服務例項列表;
這裡建立了一個RestController,查詢服務例項列表並列印所有服務,並且返回HelloWorld;
package com.service_provider.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
*
* @author yuyan
* @create 2018-10-23 14:31
**/
@RestController
public class HelloController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
DiscoveryClient client;
@RequestMapping("/hello")
public String index(){
for(String service:client.getServices()){
List<ServiceInstance> services = client.getInstances(service);
for(ServiceInstance serviceInstance:services){
logger.info("/hello, host:" + serviceInstance.getHost() + ", service_id:" + serviceInstance.getServiceId());
}
}
return "Hello World";
}
}
2.5 設定Application,通過EnableDiscoveryClient註解,讓該應用註冊成為Eureka客戶端應用;
package com.service_provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
設定完成後,執行專案,執行成功後就可以在EurekaCenter的管理介面上,檢視到服務資訊:
3、建立服務消費者
3.1 建立一個Spring Boot應用
3.2 配置pom.xml:
同樣,需要引入SpringCloud和Eureka服務端依賴,這裡多引入了一個ribbon依賴,用於實現客戶端的負載均衡,關於負載均衡,會在後面進行解釋;
<?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.ribbon_consumer</groupId>
<artifactId>ribbon_consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ribbon_consumer</name>
<description>ribbon_consumer</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<!--Finchley的SpringCloud不能使用這個-->
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-ribbon</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--</dependency>-->
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.3 配置application.properties:
server.port=9000
spring.application.name=consumer
eureka.client.service-url.defaultZone=http://localhost:1112/eureka/
3.4 配置Application主類:
與服務提供者類似,通過EnableDiscoveryClient註解,讓服務消費者註冊成為Eureka客戶端應用,並且在該主類中建立RestTemplate的SpringBoot例項,通過LoadBalanced開啟客戶端負載均衡;
package com.service_consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class ServiceConsumerApplication {
@Bean
@LoadBalanced//開啟客戶端負載均衡
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
}
3.5 建立一個RestController,用來呼叫服務提供者的服務:
通過restTemplate以get方式呼叫服務名稱為HELLO-SERVICE的hello介面,並且返回介面的結果;這裡使用的是服務名,而不是具體的ip或是域名作為訪問地址,服務名可以通過Eureka控制檯獲取,或者通過DiscoveryClient獲得服務列表;
package com.service_consumer.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class ConsumerController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/hello_consumer", method = RequestMethod.GET)
public String helloConsumer(){
return restTemplate.getForEntity("http://HELLO-SERVICE/hello/",String.class).getBody();
}
}
配置完成後,執行專案,執行成功後,開啟Eureka服務控制檯:
可以看到現在有兩個應用,分別是一個消費者和一個提供者,現在訪問localhost:9000/hello_consumer:
成功的返回了服務提供者的返回值:Hello World
至此,一個基於基於Eureka服務中心的微服務體系就搭建成功了!