Spring Cloud學習筆記1——服務治理(Eureka)
1、搭建服務註冊中心
1)新建一個Spring Boot專案,取名為EurekaServer,程式碼見碼雲:https://gitee.com/wudiyong/EurekaServer.git,然後在pom.xml檔案中加入依賴:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR6</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2)在入口類處加上@EnableEurekaServer註解,用於開啟服務註冊中心,如下:
@EnableEurekaServer
@SpringBootApplication
public class ErukaServerApplication {
public static void main(String[] args) {
SpringApplication.run(ErukaServerApplication.class, args);
}
}
3)配置application.properties
server.port=8761
eureka.instance.hostname=localhost#當前例項的主機名稱
eureka.client.register-with-eureka=false#false代表不向註冊中心註冊自己(因為本身就是註冊中心),預設是true,如果不設為false,啟動會報找不到註冊中心的錯誤
eureka.client.fetch-registry=false#註冊中心用於維護服務例項,無需檢索服務,故設為false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
eureka.client.serviceUrl.defaultZone與eureka.client.service-url.defaultZone有什麼區別?
“eureka.client.service-url.”指定服務註冊中心地址,型別為 HashMap,並設定有一組預設值,預設的Key為 defaultZone;預設的Value為http://localhost:8761/eureka ,如果服務註冊中心為高可用叢集時,多個註冊中心地址以逗號分隔。
至此,註冊中心搭建完成,訪問http://localhost:8761/可看到註冊中心資訊,如系統狀態、已註冊的服務列表等。
可以看到頁面中的environment的值是test,可以通過eureka.environment=dev來改變該值。
2、服務提供者到註冊中心註冊服務(服務註冊)
新建一個專案,取名為userInfoService,程式碼見碼雲:https://gitee.com/wudiyong/userInfoService.git
1)pom.xml檔案與註冊中心類似
2)入口類加上註解@EnableEurekaClient,開啟eureka客戶端,可以註冊服務及發現呼叫服務,與註冊中心的@EnableEurekaServer剛好相反。
@EnableDiscoveryClient也能起到該作用,@EnableDiscoveryClient與@EnableEurekaClient的關係如下:
SpringCloud中的“Discovery Service”有多種實現,比如:eureka, consul, zookeeper,可見eruka只是其中的一種。
@EnableDiscoveryClient
註解是基於spring-cloud-commons
依賴,並且在classpath中實現(根據匯入的jar包有關);@EnableEurekaClient
註解是基於spring-cloud-netflix
依賴,只能為eureka作用;
如果你的classpath中添加了eureka,則它們的作用是一樣的。
3)編寫controller類,對外提供服務,如:
@RestController
public class UserInfoController {
//@RequestBody告訴從body裡取值,請求方的Content-Type要設定為application/json,否則報415錯誤
//@RequestBody好像不能用多個,如@RequestBody String name,@RequestBody int age
@RequestMapping(value="/addUserInfo",method=RequestMethod.POST)
public String addUserInfo(@RequestBody UserInfo userInfo){
return userInfo.getName() + ":" + userInfo.getAge();
}
//@RequestParam告訴從url裡取值
@RequestMapping(value="/userInfo",method=RequestMethod.GET)
public String userInfo(@RequestParam String name,@RequestParam String age){
return name + ":" + age;
}
}
4)配置application.properties
spring.application.name=userInfo-service
server.port=1001
#指向註冊中心,http://${eureka.instance.hostname}:${server.port}/eureka/
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
5)測試
啟動服務註冊中心和服務提供者程式,再訪問http://localhost:8761/,可以看到如下資訊,說明服務已經註冊到註冊中心了:
Instances currently registered with Eureka
可以修改埠號,啟動多個userInfo-service服務,這時可以看到
3、服務發現及呼叫
服務的呼叫者若想呼叫某個服務,首先向註冊中心發起諮詢服務請求,獲取服務例項清單,可以有多個服務名相同的服務提供者,即有多個服務例項,當呼叫者發起呼叫時,會以某種輪詢策略,選擇其中一個例項進行呼叫,這涉及到客戶端(Eureka Client)負載均衡。
首先新建一個專案,取名為userInfoService,程式碼見碼雲:https://gitee.com/wudiyong/ribbonConsumer.git
1)配置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</groupId>
<artifactId>ribbonConsumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ribbonConsumer</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.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>Camden.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</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-test</artifactId>
<scope>test</scope>
</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>
2)入口類加上註解@EnableEurekaClient,同時,在該類中建立RestTemplate例項,並通過@LoadBalanced註解開啟客戶端負載均衡
@EnableEurekaClient
@SpringBootApplication
public class RibbonConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
}
3)配置application.properties
spring.application.name=ribbon-consumer
server.port=9000
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
4)編寫呼叫服務的類
@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@RequestMapping(value="/userInfo", method = RequestMethod.GET)
public String userInfo(@RequestParam String name, @RequestParam String age) {
//如果是post請求,可以用postForEntity
Map<String , Object> params = new HashMap<String , Object>();
params.put("name", name);
params.put("age", age);
return restTemplate.getForEntity("http://USERINFO-SERVICE/userInfo?name={name}&age={age}",
String.class,params).getBody();
}
}
分別啟動EurekaServer、userInfoService和userInfoService,其中userInfoService可以修改埠號來啟動多個,開啟http://localhost:8761/,可看到:
4)測試,訪問:http://www.localhost:9000/userInfo?name=殺殺殺&age=326
如果有多個USERINFO-SERVICE服務,則請求會輪詢被分配到某一個服務。
服務提供者本身也可以作為服務呼叫者,可以呼叫其它的服務,也就是說,提供者與呼叫者是相對的,一個系統可以既是服務提供者又是服務呼叫者,這一點很重要,因為服務提供者之間會互相呼叫。
4、高可用註冊中心
前面我們只使用一個註冊中心,當該註冊中心不可用時,所有的服務都不可用,解決方案是,採用多個註冊中心,註冊中心之間互相註冊,前面的註冊中心我們通過設定下面兩個引數讓註冊中心不要註冊自己:
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
現在需要把這兩行刪掉。
由於除了application.properties之外,其它程式碼都一樣,所以採用spring.profiles.active來控制載入不同的配置檔案。
假設有兩個註冊中心,則分別建立兩個配置檔案:
application-peer1.properties:
server.port=1111
spring.application.name=eureka-server
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://localhost:1112/eureka/
application-peer2.properties:
server.port=1112
spring.application.name=eureka-server
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
上面的例子中,都是通過eureka.instance.hostname設定主機名來定義例項地址的,這裡的localhost只是一個特殊的情況,系統會自動轉換為127.0.0.1,我們也可以設定為
eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/
和
eureka.instance.hostname=peer2
eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/
然後在C:\Windows\System32\drivers\etc\hosts或/etc/hosts中加入如下資訊:
127.0.0.1 peer1
127.0.0.1 peer2
這樣系統就會自動把peer1、peer2轉換成ip地址。除了以上方式,還可以直接指定ip,eureka.instance.prefer-ip-address預設是false,可以把其設為true來開啟,如果採用ip方式,則eureka.instance.hostname可以去掉,系統會自動為例項設定ip地址,如果要手動設定,可以通過eureka.instance.ip-address來設定。
例項主機名或例項ip地址不僅僅是用在註冊中心,也能用於服務的提供者和呼叫者,因為三者本質上都是一個例項。
application.properties檔案只要寫spring.profiles.active=peer1或spring.profiles.active=peer2
至此,兩個註冊中心已互相註冊成功。
服務提供者、服務呼叫者都需修改application.properties檔案,使其都註冊到這兩個註冊中心中,修改成如下:
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/,http://localhost:1112/eureka/