學習前提:
這個階段如何學習?
三層架構 + MVC
框架:
Spring(輕量級的Java開源框架):解決企業開發的複雜性 IOC、AOP
SpringBoot(Spring的升級版):新一代的JavaEE開發標準 自動裝配
模組化~ all in one
模組化的開發===all in one 程式碼沒發生變
微服務架構4個核心問題:
1. 服務很多,用戶端怎麼存取?
2. 這麼多服務,服務之間如何通訊?
3. 這麼多服務,如何治理?
4. 服務掛了怎麼辦?
解決方案選型:
SpringCloud 是一種生態! 學習前提已經會使用Springboot,有分佈式基礎,瞭解Dubbo+ZooKeeper
1. Spring Cloud NetFlix(已經停止維護):一站式解決方案!可解決上述4個核心問題
API閘道器:zuul元件
通訊:Feign ---- HttpClient ---- Http通訊方式,同步,阻塞
服務註冊和發現:Eureka
熔斷機制 機製:Hystrix
......
2. Apache Dubbo Zookeeper:半自動!需要整合別人的
API閘道器:沒有,找第三方元件(比如整合zull元件),或者自己實現
通訊:Dubbo 是一個基於Java的高效能的RPC通訊框架(效能比Feign強大)
服務註冊和發現:Zookeeper
熔斷機制 機製:沒有,需要藉助Hystrix
3. Spring Cloud Alibaba:目前最新的一站式解決方案!可解決上述4個核心問題,更簡單
API閘道器:
通訊:
服務註冊和發現:
熔斷機制 機製:
新概念:服務網格~ Server Mesh
istio
萬變不離其宗4個問題:
1. API閘道器
2. HTTP,RPC通訊
3. 註冊和發現
4. 熔斷機制 機製
1.1 什麼是微服務?
1.2 微服務之間是如何獨立通訊的?
1.3 SpringCloud 和 Dubbo有那些區別?
1.4 SpringBoot 和 SpringCloud,請談談你對他們的理解
1.5 什麼是服務熔斷?什麼是服務降級?
1.6 微服務的優缺點分別是什麼?說下你在專案開發中遇到的坑
1.7 你所知道的微服務技術棧有哪些?列舉一二
1.8 Eureka和Zookeeper都可以提供服務註冊與發現的功能,請說說兩者的區別
微服務(Microservice Architecture) 是近幾年流行的一種架構思想,關於它的概念很難一言以蔽之。
究竟什麼是微服務呢?我們在此參照ThoughtWorks 公司的首席科學家 Martin Fowler 於2014年提出的一段話:
原文:https://martinfowler.com/articles/microservices.html
漢化:https://www.cnblogs.com/liuning8023/p/4493156.html
再來從技術維度角度理解下:
微服務化的核心就是將傳統的一站式應用,根據業務拆分成一個一個的服務,徹底地去耦合,每一個微服務提供單個業務功能的服務,一個服務做一件事情,從技術角度看就是一種小而獨立的處理過程,類似進程的概念,能夠自行單獨啓動或銷燬,擁有自己獨立的數據庫。
強調的是服務的大小,它關注的是某一個點,是具體解決某一個問題/提供落地對應服務的一個服務應用,狹義的看,可以看作是IDEA中的一個個微服務工程,或者Moudel。
IDEA 工具裏面使用Maven開發的一個個獨立的小Moudel,它具體是使用SpringBoot開發的一個小模組,專業的事情交給專業的模組來做,一個模組就做着一件事情。
強調的是一個個的個體,每個個體完成一個具體的任務或者功能。
一種新的架構形式,Martin Fowler 於2014年提出。
微服務架構是一種架構模式,它體長將單一應用程式劃分成一組小的服務,服務之間相互協調,互相配合,爲使用者提供最終價值。每個服務執行在其獨立的進程中,服務與服務之間採用輕量級的通訊機制 機製
(如HTTP)互相共同作業,每個服務都圍繞着具體的業務進行構建,並且能夠被獨立的部署到生產環境中,另外,應儘量避免統一的,集中式的服務管理機制 機製,對具體的一個服務而言,應根據業務上下文,選擇合適的語言、工具(如Maven)
對其進行構建。
優點
缺點
微服務技術條目 | 落地技術 |
---|---|
服務開發 | SpringBoot、Spring、SpringMVC等 |
服務設定與管理 | Netfix公司的Archaius、阿裡的Diamond等 |
服務註冊與發現 | Eureka、Consul、Zookeeper等 |
服務呼叫 | Rest、PRC、gRPC |
服務熔斷器 | Hystrix、Envoy等 |
負載均衡 | Ribbon、Nginx等 |
服務介面呼叫(用戶端呼叫服務的簡化工具) | Fegin等 |
訊息佇列 | Kafka、RabbitMQ、ActiveMQ等 |
服務設定中心管理 | SpringCloudConfig、Chef等 |
服務路由(API閘道器) | Zuul等 |
服務監控 | Zabbix、Nagios、Metrics、Specatator等 |
全鏈路追蹤 | Zipkin、Brave、Dapper等 |
數據流操作開發包 | SpringCloud Stream(封裝與Redis,Rabbit,Kafka等發送接收訊息) |
時間訊息總棧 | SpringCloud Bus |
服務部署 | Docker、OpenStack、Kubernetes等 |
選型依據
整體解決方案和框架成熟度
社羣熱度
可維護性
學習曲線
當前各大IT公司用的微服務架構有那些?
阿裡:dubbo+HFS
京東:JFS
新浪:Motan
噹噹網:DubboX
…
功能點/服務架構 | Netflix/SpringCloud | Motan | gRPC | Thrift | Dubbo/DubboX |
---|---|---|---|---|---|
功能定位 | 完整的微服務架構 | RPC框架,但整合了ZK或Consul,實現叢集環境的基本服務註冊發現 | RPC框架 | RPC框架 | 服務架構 |
支援Rest | 是,Ribbon支援多種可拔插的序列號選擇 | 否 | 否 | 否 | 否 |
支援RPC | 否 | 是(Hession2) | 是 | 是 | 是 |
支援多語言 | 是(Rest形式) | 否 | 是 | 是 | 否 |
負載均衡 | 是(伺服器端zuul+用戶端Ribbon),zuul-服務,動態路由,雲端負載均衡Eureka(針對中間層伺服器) | 是(用戶端) | 否 | 否 | 是(用戶端) |
設定服務 | Netfix Archaius,Spring Cloud Config Server 集中設定 | 是(Zookeeper提供) | 否 | 否 | 否 |
服務呼叫鏈監控 | 是(zuul),zuul提供邊緣服務,API閘道器 | 否 | 否 | 否 | 否 |
高可用/容錯 | 是(伺服器端Hystrix+用戶端Ribbon) | 是(用戶端) | 否 | 否 | 是(用戶端) |
典型應用案例 | Netflix | Sina | |||
社羣活躍程度 | 高 | 一般 | 高 | 一般 | 2017年後重新開始維護,之前中斷了5年 |
學習難度 | 中等 | 低 | 高 | 高 | 低 |
文件豐富程度 | 高 | 一般 | 一般 | 一般 | 高 |
其他 | Spring Cloud Bus爲我們的應用程式帶來了更多管理端點 | 支援降級 | Netflix內部在開發整合gRPC | IDL定義 | 實踐的公司比較多 |
Spring官網:https://spring.io/
Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state). Coordination of distributed systems leads to boiler plate patterns, and using Spring Cloud developers can quickly stand up services and applications that implement those patterns. They will work well in any distributed environment, including the developer’s own laptop, bare metal data centres, and managed platforms such as Cloud Foundry.
翻譯:
Spring Cloud爲開發人員提供了快速構建分佈式系統中的一些常見模式的工具(例如設定管理、服務發現、斷路器、智慧路由、微代理、控制匯流排、一次性令牌、全域性鎖、領導人選舉、分佈式對談、叢集狀態)。分佈式系統的協調導致了鍋爐板模式,而使用Spring Cloud開發人員可以快速建立實現這些模式的服務和應用程式。它們在任何分佈式環境中都能很好地工作,包括開發人員自己的筆記型電腦、裸金屬數據中心和雲端計算等託管平臺。
分佈式+服務治理Dubbo
目前成熟的網際網路架構,應用服務化拆分+訊息中介軟體
Dubbo 和 SpringCloud對比
可以看一下社羣活躍度:
https://github.com/dubbo
https://github.com/spring-cloud
Dubbo | SpringCloud | |
---|---|---|
服務註冊中心 | Zookeeper | Spring Cloud Netfilx Eureka |
服務呼叫方式 | RPC | REST API |
服務監控 | Dubbo-monitor | Spring Boot Admin |
斷路器 | 不完善 | Spring Cloud Netfilx Hystrix |
服務閘道器 | 無 | Spring Cloud Netfilx Zuul |
分佈式設定 | 無 | Spring Cloud Config |
服務跟蹤 | 無 | Spring Cloud Sleuth |
訊息總棧 | 無 | Spring Cloud Bus |
數據流 | 無 | Spring Cloud Stream |
批次任務 | 無 | Spring Cloud Task |
最大區別:Spring Cloud 拋棄了Dubbo的RPC通訊,採用的是基於HTTP的REST方式
嚴格來說,這兩種方式各有優劣。雖然從一定程度上來說,後者犧牲了服務呼叫的效能,但也避免了上面提到的原生RPC帶來的問題。而且REST相比RPC更爲靈活,服務提供方和呼叫方的依賴只依靠一紙契約,不存在程式碼級別的強依賴,這個優點在當下強調快速演化的微服務環境下,顯得更加合適。
品牌機和組裝機的區別
社羣支援與更新力度的區別
二者解決的問題域不一樣:Dubbo的定位是一款RPC框架,而SpringCloud的目標是微服務架構下的一站式解決方案。
官網:http://projects.spring.io/spring-cloud/
版本號有點特別:
SpringCloud沒有採用數位編號的方式命名版本號,而是採用了倫敦地鐵站的名稱,同時根據字母表的順序來對應版本時間順序,比如最早的Realse版本:Angel,第二個Realse版本:Brixton,然後是Camden、Dalston、Edgware,目前最新的是Hoxton SR4 CURRENT GA通用穩定版
自學參考書:
我們會使用一個Dept部門模組做一個微服務通用案例Consumer消費者(Client)通過REST呼叫Provider提供者(Server)提供的服務。
回顧Spring,SpringMVC,Mybatis等以往學習的知識。
Maven的分包分模組架構複習。
一個簡單的Maven模組結構是這樣的:
-- app-parent: 一個父專案(app-parent)聚合了很多子專案(app-util\app-dao\app-web...)
|-- pom.xml
|
|-- app-core
||---- pom.xml
|
|-- app-web
||---- pom.xml
......
一個父工程帶着多個Moudule子模組
MicroServiceCloud父工程(Project)下初次帶着3個子模組(Module)
microservicecloud-api 【封裝的整體entity/介面/公共設定等】
microservicecloud-consumer-dept-80 【服務提供者】
microservicecloud-provider-dept-8001 【服務消費者】
SpringBoot | SpringCloud | 關係 |
---|---|---|
1.2.x | Angel版本(天使) | 相容SpringBoot1.2x |
1.3.x | Brixton版本(布裡克斯頓) | 相容SpringBoot1.3x,也相容SpringBoot1.4x |
1.4.x | Camden版本(卡姆登) | 相容SpringBoot1.4x,也相容SpringBoot1.5x |
1.5.x | Dalston版本(多爾斯頓) | 相容SpringBoot1.5x,不相容SpringBoot2.0x |
1.5.x | Edgware版本(埃奇韋爾) | 相容SpringBoot1.5x,不相容SpringBoot2.0x |
2.0.x | Finchley版本(芬奇利) | 相容SpringBoot2.0x,不相容SpringBoot1.5x |
2.1.x | Greenwich版本(格林威治) |
spring-boot-starter-parent | spring-cloud-dependencles | ||
---|---|---|---|
版本號 | 發佈日期 | 版本號 | 發佈日期 |
1.5.2.RELEASE | 2017-03 | Dalston.RC1 | 2017-x |
1.5.9.RELEASE | 2017-11 | Edgware.RELEASE | 2017-11 |
1.5.16.RELEASE | 2018-04 | Edgware.SR5 | 2018-10 |
1.5.20.RELEASE | 2018-09 | Edgware.SR5 | 2018-10 |
2.0.2.RELEASE | 2018-05 | Fomchiey.BULD-SNAPSHOT | 2018-x |
2.0.6.RELEASE | 2018-10 | Fomchiey-SR2 | 2018-10 |
2.1.4.RELEASE | 2019-04 | Greenwich.SR1 | 2019-03 |
使用後兩個
新建父工程專案springcloud,切記Packageing是pom模式(刪除父工程src)
主要是定義POM檔案,將後續各個子模組公用的jar包等統一提取出來
父類別pom.xml
(預留位置)
父工程爲springcloud,其下有多個子mudule
建立第一個模組 springcloud-api 公共介面
子模組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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.kuang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-api</artifactId>
<!--當前的Module自己需要的依賴,如果父依賴中已經設定了版本。這裏就不用寫了-->
<dependencies>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
只需要寫一個pojo
Dept.java
package com.kuang.springcloud.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.omg.CosNaming.NamingContextExtPackage.StringNameHelper;
import java.io.Serializable;
/**
* @program: springcloud
* @description:
* @author: Mr.Luo
* @create: 2020-08-01 10:36
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class Dept implements Serializable {
//Dept實體類 類表關係對映
private long deptno;
private String dname;
//這個數據是存在哪個數據庫的欄位?微服務,一個服務對應一個數據庫,同一個資訊可能存在不同的額數據庫
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
/* 鏈式寫法
Dept dept = new Dept();
dept.setDepNo(11).setDname("sss").setDB_source("001")
*/
}
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.kuang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-dept-8001</artifactId>
<dependencies>
<!--config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--EUREKA-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--actuator完善監控資訊-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--我們需要拿到實體類,所以要設定api module-->
<dependency>
<groupId>com.kuang</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!--熱部署工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
DeptController.java
package com.kuang.springcloud.controller;
import com.kuang.springcloud.pojo.Dept;
import com.kuang.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @program: springcloud
* @description:
* @author: Mr.Luo
* @create: 2020-08-01 12:03
*/
//提供Restful服務
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id")Long id){
return deptService.queryById(id);
}
@GetMapping("/dept/list")
public List queryAll(Dept dept){
return deptService.queryAll();
}
}
DeptDao.java
package com.kuang.springcloud.dao;
import com.kuang.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @program: springcloud
* @description:
* @author: Mr.Luo
* @create: 2020-08-01 11:52
*/
@Mapper
@Repository //表示它是dao層的東西哎
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(long id);
public List<Dept> queryAll();
}
DeptService.java
package com.kuang.springcloud.service;
import com.kuang.springcloud.pojo.Dept;
import java.util.List;
/**
* @program: springcloud
* @description:
* @author: Mr.Luo
* @create: 2020-08-01 12:00
*/
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(long id);
public List<Dept> queryAll();
}
DeptServiceImpl.java
package com.kuang.springcloud.service;
import com.kuang.springcloud.dao.DeptDao;
import com.kuang.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @program: springcloud
* @description:
* @author: Mr.Luo
* @create: 2020-08-01 12:01
*/
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
@Override
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept queryById(long id) {
return deptDao.queryById(id);
}
@Override
public List<Dept> queryAll() {
return deptDao.queryAll();
}
}
DeptProvider_8001.java SpringBoot啓動類
package com.kuang.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @program: springcloud
* @description:
* @author: Mr.Luo
* @create: 2020-08-01 23:53
*/
@SpringBootApplication
@EnableEurekaClient //在服務啓動後,自動註冊到Eureka中(CS模式)
public class DeptProvider_8001 {
public static void main(String[] args){
SpringApplication.run(DeptProvider_8001.class,args);
}
}
application.yml
server:
port: 8001
# mybatis設定
mybatis:
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
type-aliases-package: com.kuang.springcloud.pojo
# Spring設定
spring:
application:
name: spring-cloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: admin
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
DeptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.springcloud.dao.DeptDao">
<insert id="addDept" parameterType="Dept">
insert into dept (dname, db_source)
VALUES (#(dname),DATABASE());
</insert>
<select id="queryById" resultType="Dept" parameterType="Long">
select * from dept where deptno=#(deptno);
</select>
<select id="queryAll" resultType="Dept">
select * from dept;
</select>
</mapper>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 開啓二級快取-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
存取:http://localhost:8001/dept/list
測試成功
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.kuang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-dept-80</artifactId>
<dependencies>
<dependency>
<groupId>com.kuang</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
DeptConsumerController.java
package com.kuang.springcloud.controller;
import com.kuang.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
// 理解:消費者,不應該有service層~
// RestTemplate .... 供我們直接呼叫就可以了! 註冊到Spring中
// (url, 實體:Map ,Class<T> responseType)
@Autowired
private RestTemplate restTemplate; //提供多種便捷存取遠端http服務的方法,簡單的Restful服務模板~
//Ribbon。我們這裏的地址,應該是一個變數,通過服務名來存取
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://localhost:8001";
//private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
}
DeptConsumer_80.java
package com.kuang.springcloud;
//import com.kuang.myrule.KuangRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
//import org.springframework.cloud.netflix.ribbon.RibbonClient;
//Ribbon 和 Eureka 整合以後,用戶端可以直接呼叫,不用關心IP地址和埠號~
@SpringBootApplication
//@EnableEurekaClient
//在微服務啓動的時候就能去載入我們自定義Ribbon類
//@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = KuangRule.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
application.yml
80埠被佔用,換成了8002埠,測試成功
server:
port: 8002
存取:http://localhost:8002/consumer/dept/list
測試成功
Springcloud 封裝了Netflix公司開發的Eureka模組來實現服務註冊與發現 (對比Zookeeper).
Eureka採用了C-S的架構設計,EurekaServer作爲服務註冊功能的伺服器,他是服務註冊中心.
而系統中的其他微服務,使用Eureka的用戶端連線到EurekaServer並維持心跳連線。這樣系統的維護人員就可以通過EurekaServer來監控系統中各個微服務是否正常執行,Springcloud 的一些其他模組 (比如Zuul) 就可以通過EurekaServer來發現系統中的其他微服務,並執行相關的邏輯.
Eureka 包含兩個元件:Eureka Server 和 Eureka Client.
Eureka Server 提供服務註冊,各個節點啓動後,回在EurekaServer中進行註冊,這樣Eureka Server中的服務註冊表中將會儲存所有課用服務節點的資訊,服務節點的資訊可以在介面中直觀的看到.
Eureka Client 是一個Java用戶端,用於簡化EurekaServer的互動,用戶端同時也具備一個內建的,使用輪詢負載演算法的負載均衡器。在應用啓動後,將會向EurekaServer發送心跳 (預設週期爲30秒) 。如果Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將會從服務註冊表中把這個服務節點移除掉 (預設週期爲90s).
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.kuang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-eureka-7001</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--熱部署工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
EurekaServer_7001.java
package com.kuang.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
//啓動之後,存取 http://localhost:7001/
@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer 伺服器端的啓動類,可以接受別人註冊進來~
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
application.yml
server:
port: 7001
#Eureka設定
eureka:
instance:
hostname: localhost #Eureka伺服器端的範例名稱
client:
register-with-eureka: false # 表示是否向eureka註冊中心註冊自己,這裏寫的是伺服器,不需要註冊
fetch-registry: false #fetch-registry如果爲false,則表示自己爲註冊中心
service-url: # 監控頁面
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 叢集(關聯):
# defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
note:
1.匯入依賴
2.編寫組態檔
3.開啓這個功能 @EnableXXXXX
4.設定類
效果:
效果:
點選鏈接之後,跳轉頁面
如果此時停掉springcloud-provider-dept-8001 等30s後 監控會開啓保護機制 機製
一句話總結就是:某時刻某一個微服務不可用,eureka不會立即清理,依舊會對該微服務的資訊進行儲存!
預設情況下,當eureka server在一定時間內沒有收到範例的心跳,便會把該範例從註冊表中刪除(預設是90秒),但是,如果短時間內丟失大量的範例心跳,便會觸發eureka server的自我保護機制 機製,比如在開發測試時,需要頻繁地重新啓動微服務範例,但是我們很少會把eureka server一起重新啓動(因爲在開發過程中不會修改eureka註冊中心),當一分鐘內收到的心跳數大量減少時,會觸發該保護機制 機製。可以在eureka管理介面看到Renews threshold和Renews(last min),當後者(最後一分鐘收到的心跳數)小於前者(心跳閾值)的時候,觸發保護機制 機製,會出現紅色的警告:**EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.**從警告中可以看到,eureka認爲雖然收不到範例的心跳,但它認爲範例還是健康的,eureka會保護這些範例,不會把它們從註冊表中刪掉。
該保護機制 機製的目的是避免網路連線故障,在發生網路故障時,微服務和註冊中心之間無法正常通訊,但服務本身是健康的,不應該註銷該服務,如果eureka因網路故障而把微服務誤刪了,那即使網路恢復了,該微服務也不會重新註冊到eureka server了,因爲只有在微服務啓動的時候纔會發起註冊請求,後面只會發送心跳和服務列表請求,這樣的話,該範例雖然是執行着,但永遠不會被其它服務所感知。所以,eureka server在短時間內丟失過多的用戶端心跳時,會進入自我保護模式,該模式下,eureka會保護註冊表中的資訊,不在註銷任何微服務,當網路故障恢復後,eureka會自動退出保護模式。自我保護模式可以讓叢集更加健壯。
但是我們在開發測試階段,需要頻繁地重啓發布,如果觸發了保護機制 機製,則舊的服務範例沒有被刪除,這時請求有可能跑到舊的範例中,而該範例已經關閉了,這就導致請求錯誤,影響開發測試。所以,在開發測試階段,我們可以把自我保護模式關閉,只需在eureka server組態檔中加上如下設定即可:eureka.server.enable-self-preservation=false
詳細內容可以參考下這篇部落格內容:https://blog.csdn.net/wudiyong22/article/details/80827594
註冊進來的微服務,獲取一些訊息~
//獲取一些設定的資訊,得到具體的微服務!
@Autowired
private DiscoveryClient client;
//註冊進來的微服務~,獲取一些訊息~
@GetMapping("/dept/discovery")
public Object discovery() {
//獲取微服務列表的清單
List<String> services = client.getServices();
System.out.println("discovery=>services:" + services);
//得到一個具體的微服務資訊,通過具體的微服務id,applicaioinName;
List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost() + "\t" + // 主機名稱
instance.getPort() + "\t" + // 埠號
instance.getUri() + "\t" + // uri
instance.getServiceId() // 服務id
);
}
return this.client;
}
新建springcloud-eureka-7002、springcloud-eureka-7003 模組
1.爲pom.xml新增依賴 (與springcloud-eureka-7001相同)
<!--導包~-->
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<!--匯入Eureka Server依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--熱部署工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
2.application.yml設定(與springcloud-eureka-7001相同)
server:
port: 7003
#Eureka設定
eureka:
instance:
hostname: localhost #Eureka伺服器端的範例名字
client:
register-with-eureka: false #表示是否向 Eureka 註冊中心註冊自己(這個模組本身是伺服器,所以不需要)
fetch-registry: false #fetch-registry如果爲false,則表示自己爲註冊中心
service-url: #監控頁面~
#重寫Eureka的預設埠以及存取路徑 --->http://localhost:7001/eureka/
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.主啓動類(與springcloud-eureka-7001相同)
//啓動之後,存取 http://localhost:7001/
@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer 伺服器端的啓動類,可以接受別人註冊進來~
public class EurekaServer_7003 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7003.class,args);
}
}
設定一些自定義本機名字,找到本機hosts檔案並開啓
修改application.yml的設定,如圖爲springcloud-eureka-7001設定,springcloud-eureka-7002/springcloud-eureka-7003同樣分別修改爲其對應的名稱即可
在叢集中使springcloud-eureka-7001關聯springcloud-eureka-7002、springcloud-eureka-7003
完整的springcloud-eureka-7001下的application.yml如下
server:
port: 7001
#Eureka設定
eureka:
instance:
hostname: eureka7001.com #Eureka伺服器端的範例名字
client:
register-with-eureka: false #表示是否向 Eureka 註冊中心註冊自己(這個模組本身是伺服器,所以不需要)
fetch-registry: false #fetch-registry如果爲false,則表示自己爲註冊中心
service-url: #監控頁面~
#重寫Eureka的預設埠以及存取路徑 --->http://localhost:7001/eureka/
# 單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 叢集(關聯):7001關聯7002、7003
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
同時在叢集中使springcloud-eureka-7002關聯springcloud-eureka-7001、springcloud-eureka-7003
完整的springcloud-eureka-7002下的application.yml如下
server:
port: 7002
#Eureka設定
eureka:
instance:
hostname: eureka7002.com #Eureka伺服器端的範例名字
client:
register-with-eureka: false #表示是否向 Eureka 註冊中心註冊自己(這個模組本身是伺服器,所以不需要)
fetch-registry: false #fetch-registry如果爲false,則表示自己爲註冊中心
service-url: #監控頁面~
#重寫Eureka的預設埠以及存取路徑 --->http://localhost:7001/eureka/
# 單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 叢集(關聯):7002關聯7001、7003
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
springcloud-eureka-7003設定方式同理可得.
通過springcloud-provider-dept-8001下的yml組態檔,修改Eureka設定:設定服務註冊中心地址
# Eureka設定:設定服務註冊中心地址
eureka:
client:
service-url:
# 註冊中心地址7001-7003
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-dept-8001 #修改Eureka上的預設描述資訊
這樣模擬叢集就搭建號了,就可以把一個專案掛載到三個伺服器上了
CAP的三進二:CA、AP、CP
Zookeeper保證的是CP
當向註冊中心查詢服務列表時,我們可以容忍註冊中心返回的是幾分鐘以前的註冊資訊,但不能接收服務直接down掉不可用。也就是說,服務註冊功能對可用性的要求要高於一致性。但zookeeper會出現這樣一種情況,當master節點因爲網路故障與其他節點失去聯繫時,剩餘節點會重新進行leader選舉。問題在於,選舉leader的時間太長,30-120s,且選舉期間整個zookeeper叢集是不可用的,這就導致在選舉期間註冊服務癱瘓。在雲部署的環境下,因爲網路問題使得zookeeper叢集失去master節點是較大概率發生的事件,雖然服務最終能夠恢復,但是,漫長的選舉時間導致註冊長期不可用,是不可容忍的。
Eureka保證的是AP
Eureka看明白了這一點,因此在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩餘的節點依然可以提供註冊和查詢服務。而Eureka的用戶端在向某個Eureka註冊時,如果發現連線失敗,則會自動切換至其他節點,只要有一臺Eureka還在,就能保住註冊服務的可用性,只不過查到的資訊可能不是最新的,除此之外,Eureka還有之中自我保護機制 機製,如果在15分鐘內超過85%的節點都沒有正常的心跳,那麼Eureka就認爲用戶端與註冊中心出現了網路故障,此時會出現以下幾種情況:
因此,Eureka可以很好的應對因網路故障導致部分節點失去
聯繫的情況,而不會像zookeeper那樣使整個註冊服務癱瘓
Ribbon是什麼?
Ribbon能幹嘛?
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka: Ribbon需要從Eureka服務中心獲取要拿什麼-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
# Eureka設定
eureka:
client:
register-with-eureka: false # 不向 Eureka註冊自己
service-url: # 從三個註冊中心中隨機取一個去存取
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
//Ribbon 和 Eureka 整合以後,用戶端可以直接呼叫,不用關心IP地址和埠號
@SpringBootApplication
@EnableEurekaClient //開啓Eureka 用戶端
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
@Configuration
public class ConfigBean {//@Configuration -- spring applicationContext.xml
@LoadBalanced //設定負載均衡實現RestTemplate
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
//Ribbon:我們這裏的地址,應該是一個變數,通過服務名來存取
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
流程圖:
1.新建兩個服務提供者Moudle:springcloud-provider-dept-8003、springcloud-provider-dept-8002
2.參照springcloud-provider-dept-8001 依次爲另外兩個Moudle新增pom.xml依賴 、resourece下的mybatis和application.yml設定,Java程式碼
3.啓動所有服務測試(根據自身電腦設定決定啓動服務的個數),存取http://eureka7001.com:7001/檢視結果
測試存取http://localhost/consumer/dept/list 這時候隨機存取的是服務提供者8003
再次存取http://localhost/consumer/dept/list這時候隨機的是服務提供者8001
以上這種每次存取http://localhost/consumer/dept/list隨機存取叢集中某個服務提供者,這種情況叫做輪詢,輪詢演算法在SpringCloud中可以自定義。
在springcloud-provider-dept-80模組下的ConfigBean中進行設定,切換使用不同的規則
@Configuration
public class ConfigBean {//@Configuration -- spring applicationContext.xml
/**
* IRule:
* RoundRobinRule 輪詢
* RandomRule 隨機
* AvailabilityFilteringRule : 會先過濾掉,跳閘,存取故障的服務~,對剩下的進行輪詢~
* RetryRule : 會先按照輪詢獲取服務~,如果服務獲取失敗,則會在指定的時間內進行,重試
*/
@LoadBalanced //設定負載均衡實現RestTemplate
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Bean
public IRule myRule(){
return new RandomRule();//使用隨機規則
}
}
也可以自定義規則,在myRule包下自定義一個設定類MyRule.java,注意:該包不要和主啓動類所在的包同級,要跟啓動類所在包同級:
MyRule.java
/**
* @Auther: csp1999
* @Date: 2020/05/19/11:58
* @Description: 自定義規則
*/
@Configuration
public class MyRule {
@Bean
public IRule myRule(){
return new MyRandomRule();//預設是輪詢RandomRule,現在自定義爲自己的
}
}
主啓動類開啓負載均衡並指定自定義的MyRule設定類
//Ribbon 和 Eureka 整合以後,用戶端可以直接呼叫,不用關心IP地址和埠號
@SpringBootApplication
@EnableEurekaClient
//在微服務啓動的時候就能載入自定義的Ribbon類(自定義的規則會覆蓋原有預設的規則)
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//開啓負載均衡,並指定自定義的規則
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
自定義的規則(這裏我們參考Ribbon中預設的規則程式碼自己稍微改動):
MyRandomRule.java
public class MyRandomRule extends AbstractLoadBalancerRule {
/**
* 每個服務存取5次則換下一個服務(總共3個服務)
* <p>
* total=0,預設=0,如果=5,指向下一個服務節點
* index=0,預設=0,如果total=5,index+1
*/
private int total = 0;//被呼叫的次數
private int currentIndex = 0;//當前是誰在提供服務
//@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();//獲得當前活着的服務
List<Server> allList = lb.getAllServers();//獲取所有的服務
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
//int index = chooseRandomInt(serverCount);//生成區間亂數
//server = upList.get(index);//從或活着的服務中,隨機獲取一個
//=====================自定義程式碼=========================
if (total < 5) {
server = upList.get(currentIndex);
total++;
} else {
total = 0;
currentIndex++;
if (currentIndex > upList.size()) {
currentIndex = 0;
}
server = upList.get(currentIndex);//從活着的服務中,獲取指定的服務來進行操作
}
//======================================================
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
核心總結:
- 80匯入ribbon依賴
- 編寫application.yml組態檔(去哪裏獲取)
- 在Restful增加一個註解@LoadBalance
- 自定義的話,在啓動類外面建立一個包,自定義Rule
Feign是宣告式Web Service用戶端,它讓微服務之間的呼叫變得更簡單,類似controller呼叫service。SpringCloud整合了Ribbon和Eureka,可以使用Feigin提供負載均衡的http用戶端
只需要建立一個介面,然後新增註 加注解即可~
Feign,主要是社羣版,大家都習慣面向介面程式設計。這個是很多開發人員的規範。呼叫微服務存取兩種方法
Feign能幹什麼?
Feign預設整合了Ribbon
利用Ribbon維護了MicroServiceCloud-Dept的服務列表資訊,並且通過輪詢實現了用戶端的負載均衡,而與Ribbon不同的是,通過Feign只需要定義服務系結介面且以宣告式的方法,優雅而簡單的實現了服務呼叫。
<!--Feign的依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
通過Ribbon實現:—原來的controller:
DeptConsumerController.java
package com.haust.springcloud.controller;
import com.haust.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @Auther: csp1999
* @Date: 2020/05/17/22:44
* @Description:
*/
@RestController
public class DeptConsumerController {
// 理解:消費者,不應該有service層~
// RestTemplate .... 供我們直接呼叫就可以了! 註冊到Spring中
// (url, 實體:Map ,Class<T> responseType)
@Autowired
private RestTemplate restTemplate; //提供多種便捷存取遠端http服務的方法,簡單的Restful服務模板~
//Ribbon:我們這裏的地址,應該是一個變數,通過服務名來存取
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept) {
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list() {
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
}
}
通過Feign實現:—改造後controller:DeptConsumerController.java
@RestController
public class DeptConsumerController {
@Autowired
private DeptClientService deptClientService = null;
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept) {
return this.deptClientService.addDept(dept);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return this.deptClientService.queryById(id);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list() {
return this.deptClientService.queryAll();
}
}
Feign和Ribbon二者對比,前者顯現出面向介面程式設計特點,程式碼看起來更清爽
主設定類
@SpringBootApplication
@EnableEurekaClient
//feign用戶端註解,並指定要掃描的包以及設定介面DeptClientService
@EnableFeignClients(basePackages = {"com.haust.springcloud"})
//掃描所有自己的包,讓所有註解也能生效
@ComponentScan("com.haust.springcloud")
public class FeignDeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(FeignDeptConsumer_80.class, args);
}
}
pom.xml新增feign依賴
<!--Feign的依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
新建service包,並新建DeptClientService.java介面,
//@FeignClient:微服務用戶端註解,value:指定微服務的名字,這樣就可以使Feign用戶端直接找到對應的微服務
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public Dept queryAll();
@GetMapping("/dept/add")
public Dept addDept(Dept dept);
}
7.3 Feign和Ribbon如何選擇?
根據個人習慣而定,如果喜歡REST風格使用Ribbon;如果喜歡社羣版的面向介面風格使用Feign.
相比而言:
Ribbon需要寫一個服務名
Feign不需要,依賴Service提供服務
分佈式系統面臨的問題
複雜分佈式體系結構中的應用程式有數十個依賴關係,每個依賴關係在某些時候將不可避免失敗!
多個微服務之間呼叫的時候,假設微服務A呼叫微服務B和微服務C,微服務B和微服務C又呼叫其他的微服務,這就是所謂的「扇出」,如果扇出的鏈路上某個微服務的呼叫響應時間過長,或者不可用,對微服務A的呼叫就會佔用越來越多的系統資源,進而引起系統崩潰,所謂的「雪崩效應」。
對於高流量的應用來說,單一的後端依賴可能會導致所有伺服器上的所有資源都在幾十秒內飽和。比失敗更糟糕的是,這些應用程式還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生更多的級聯故障,這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關係的失敗,不能取消整個應用程式或系統。
我們需要,棄車保帥
Hystrix是一個應用於處理分佈式系統的延遲和容錯的開源庫,在分佈式系統裡,許多依賴不可避免的會呼叫失敗,比如超時,異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整個體系服務失敗,避免級聯故障,以提高分佈式系統的彈性。
「斷路器」本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控 (類似熔斷保險絲) ,向呼叫方方茴一個服務預期的,可處理的備選響應 (FallBack) ,而不是長時間的等待或者拋出呼叫方法無法處理的異常,這樣就可以保證了服務呼叫方的執行緒不會被長時間,不必要的佔用,從而避免了故障在分佈式系統中的蔓延,乃至雪崩。
當一切正常時,請求流可以如下所示:
當許多後端系統中有一個潛在時,它可以阻止整個使用者請求:
隨着大容量通訊量的增加,單個後端依賴項的潛在性會導致所有伺服器上的所有資源在幾秒鐘內飽和。
應用程式中通過網路或用戶端庫可能導致網路請求的每個點都是潛在故障的來源。比失敗更糟糕的是,這些應用程式還可能導致服務之間的延遲增加,從而備份佇列、執行緒和其他系統資源,從而導致更多跨系統的級聯故障。
當使用hystrix包裝每個基礎依賴項時,上面的圖表中所示的體系結構會發生類似於以下關係圖的變化。每個依賴項是相互隔離的,限制在延遲發生時它可以填充的資源中,幷包含在回退邏輯中,該邏輯決定在依賴項中發生任何型別的故障時要做出什麼樣的響應:
官網資料:https://github.com/Netflix/Hystrix/wiki
什麼是服務熔斷
新建springcloud-provider-dept-hystrix-8001模組並拷貝springcloud-provider-dept–8001內的pom.xml、resource和Java程式碼進行初始化並調整。
匯入hystrix依賴
<!--匯入Hystrix依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
調整yml組態檔
server:
port: 8001
# mybatis設定
mybatis:
# springcloud-api 模組下的pojo包
type-aliases-package: com.haust.springcloud.pojo
# 本模組下的mybatis-config.xml核心組態檔類路徑
config-location: classpath:mybatis/mybatis-config.xml
# 本模組下的mapper組態檔類路徑
mapper-locations: classpath:mybatis/mapper/*.xml
# spring設定
spring:
application:
#專案名
name: springcloud-provider-dept
datasource:
# 德魯伊數據源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: root
# Eureka設定:設定服務註冊中心地址
eureka:
client:
service-url:
# 註冊中心地址7001-7003
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-dept-hystrix-8001 #修改Eureka上的預設描述資訊
prefer-ip-address: true #改爲true後預設顯示的是ip地址而不再是localhost
#info設定
info:
app.name: haust-springcloud #專案的名稱
company.name: com.haust #公司的名稱
prefer-ip-address: false:
prefer-ip-address: true:
修改controller
//提供Restful服務
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@HystrixCommand(fallbackMethod = "hystrixGet")//如果根據id查詢出現異常,走這段程式碼
@GetMapping("/dept/get/{id}")//根據id查詢
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept==null){
throw new RuntimeException("這個id=>"+id+",不存在該使用者,或資訊無法找到~");
}
return dept;
}
//根據id查詢備選方案(熔斷)
public Dept hystrixGet(@PathVariable("id") Long id){
return new Dept().setDeptno(id)
.setDname("這個id=>"+id+",沒有對應的資訊,null---@Hystrix~")
.setDb_source("在MySQL中沒有這個數據庫");
}
}
爲主啓動類新增對熔斷的支援註解@EnableCircuitBreaker
@SpringBootApplication
@EnableEurekaClient //EnableEurekaClient 用戶端的啓動類,在服務啓動後自動向註冊中心註冊服務
@EnableCircuitBreaker//新增對熔斷的支援註解
public class HystrixDeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDeptProvider_8001.class,args);
}
}
測試:
使用熔斷後,當存取一個不存在的id時,前臺頁展示數據如下
而不使用熔斷的springcloud-provider-dept–8001模組存取相同地址會出現下面 下麪狀況
因此,爲了避免因某個微服務後臺出現異常或錯誤而導致整個應用或網頁報錯,使用熔斷是必要的
總結:
- 匯入依賴
- 編寫熔斷機制 機製+註解
- 開啓熔斷機制 機製
由上圖可得,當某一時間內服務A的存取量暴增,而B和C的存取量較少,爲了緩解A服務的壓力,這時候需要B和C暫時關閉一些服務功能,去承擔A的部分服務,從而爲A分擔壓力,叫做服務降級。
1)超時降級:主要設定好超時時間和超時重試次數和機制 機製,並使用非同步機制 機製探測回覆 回復情況
2)失敗次數降級:主要是一些不穩定的api,當失敗呼叫次數達到一定閥值自動降級,同樣要使用非同步機制 機製探測回覆 回復情況
3)故障降級:比如要呼叫的遠端服務掛掉了(網路故障、DNS故障、http服務返回錯誤的狀態碼、rpc服務拋出異常),則可以直接降級。降級後的處理方案有:預設值(比如庫存服務掛了,返回預設現貨)、兜底數據(比如廣告掛了,返回提前準備好的一些靜態頁面)、快取(之前暫存的一些快取數據)
4)限流降級:秒殺或者搶購一些限購商品時,此時可能會因爲存取量太大而導致系統崩潰,此時會使用限流來進行限制存取量,當達到限流閥值,後續請求會被降級;降級後的處理方案可以是:排隊頁面(將使用者導流到排隊頁面等一會重試)、無貨(直接告知使用者沒貨了)、錯誤頁(如活動太火爆了,稍後重試)。
在springcloud-api模組下的service包中新建降級設定類DeptClientServiceFallBackFactory.java
//降級 ~
@Component
public class DeptClientServiceFallBackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable cause) {
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept()
.setDeptno(id)
.setDname("id=>" + id + "沒有對應的資訊,用戶端提供了降級的資訊,這個服務現在已經被關閉")
.setDb_source("沒有數據~");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public Boolean addDept(Dept dept) {
return false;
}
};
}
}
在DeptClientService中指定降級設定類DeptClientServiceFallBackFactory
@Component //註冊到spring容器中
//@FeignClient:微服務用戶端註解,value:指定微服務的名字,這樣就可以使Feign用戶端直接找到對應的微服務
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)//fallbackFactory指定降級設定類
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@GetMapping("/dept/add")
public Boolean addDept(Dept dept);
}
在springcloud-consumer-dept-feign模組中開啓降級
server:
port: 80
# Eureka設定
eureka:
client:
register-with-eureka: false # 不向 Eureka註冊自己
service-url: # 從三個註冊中心中隨機取一個去存取
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
# 開啓降級feign.hystrix
feign:
hystrix:
enabled: true
- 限流:限制併發的請求存取量,超過閾值則拒絕;
- 降級:服務分優先順序,犧牲非核心服務(不可用),保證核心服務穩定;從整體負荷考慮;
- 熔斷:依賴的下遊服務故障觸發熔斷,避免引發本系 本係統崩潰;系統自動執行和恢復
新建springcloud-consumer-hystrix-dashboard模組
新增依賴
<!--Hystrix依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifact
<version>1.4.6.RELEASE</version>
</dependency>
<!--dashboard依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactI
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactI
<version>1.4.6.RELEASE</version>
</dependency>
<!--實體類+web-->
<dependency>
<groupId>com.haust</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
主啓動類
@SpringBootApplication
//開啓Dashboard
@EnableHystrixDashboard
public class DeptConsumerDashboard_9001 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumerDashboard_9001.class,args);
}
}
給springcloud-provider-dept-8001模組下的主啓動類新增如下程式碼,新增監控
@SpringBootApplication
@EnableEurekaClient //EnableEurekaClient 用戶端的啓動類,在服務啓動後自動向註冊中心註冊服務
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
//增加一個 Servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
//存取該頁面就是監控頁面
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
總結:
- 匯入dashboard依賴,
- 編寫埠設定
- 開啓服務,即對熔斷的支援
概述
什麼是zuul?
Zull包含了對請求的路由(用來跳轉的)和過濾兩個最主要功能:
其中路由功能負責將外部請求轉發到具體的微服務範例上,是實現外部存取統一入口的基礎,而過濾器功能則負責對請求的處理過程進行幹預,是實現請求校驗,服務聚合等功能的基礎。Zuul和Eureka進行整合,將Zuul自身註冊爲Eureka服務治理下的應用,同時從Eureka中獲得其他服務的訊息,也即以後的存取微服務都是通過Zuul跳轉後獲得。
注意:Zuul服務最終還是會註冊進Eureka
提供:代理+路由+過濾 三大功能!
Zuul能幹嘛?
新建springcloud-zuul模組,並匯入依賴
<dependencies>
<!--匯入zuul依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId
<version>1.4.6.RELEASE</version>
</dependency>
<!--Hystrix依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifac
<version>1.4.6.RELEASE</version>
</dependency>
<!--dashboard依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboar
<version>1.4.6.RELEASE</version>
</dependency>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifact
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifact
<version>1.4.6.RELEASE</version>
</dependency>
<!--實體類+web-->
<dependency>
<groupId>com.haust</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9527
spring:
application:
name: springcloud-zuul #微服務名稱
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance: #範例的id
instance-id: zuul9527.com
prefer-ip-address: true # 顯示ip
info:
app.name: haust.springcloud #專案名稱
company.name: haust #公司名稱
zuul:
routes:
mydept.serviceId: springcloud-provider-dept
mydept.path: /mydept/**
ignored-services: "*" # 不能再使用某個(*:全部)路徑訪問了,ignored : 忽略,隱藏全部的~
prefix: /kuagn # 設定公共的字首,實現隱藏原有路由
主啓動類
@SpringBootApplication
@EnableZuulProxy //開啓Zuul
public class ZuulApplication_9527 {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication_9527.class,args);
}
}
詳情參考springcloud中文社羣zuul元件 :https://www.springcloud.cc/spring-cloud-greenwich.html#_router_and_filter_zuul
Dalston.RELEASE
Spring Cloud Config爲分佈式系統中的外部設定提供伺服器和用戶端支援。使用Config Server,您可以在所有環境中管理應用程式的外部屬性。用戶端和伺服器上的概念對映與Spring Environment和PropertySource抽象相同,因此它們與Spring應用程式非常契合,但可以與任何以任何語言執行的應用程式一起使用。隨着應用程式通過從開發人員到測試和生產的部署流程,您可以管理這些環境之間的設定,並確定應用程式具有遷移時需要執行的一切。伺服器儲存後端的預設實現使用git,因此它輕鬆支援標籤版本的設定環境,以及可以存取用於管理內容的各種工具。很容易新增替代實現,並使用Spring設定將其插入。
微服務意味着要將單體應用中的業務拆分成一個個子服務,每個服務的粒度相對較小,因此係統中會出現大量的服務,由於每個服務都需要必要的設定資訊才能 纔能執行,所以一套集中式的,動態的設定管理設施是必不可少的。spring cloud提供了configServer來解決這個問題,我們每一個微服務自己帶着一個application.yml,那上百個的組態檔修改起來,令人頭疼!
spring cloud config 爲微服務架構中的微服務提供集中化的外部支援,設定伺服器爲各個不同微服務應用的所有環節提供了一箇中心化的外部設定。
spring cloud config 分爲伺服器端和用戶端兩部分。
伺服器端也稱爲 分佈式設定中心,它是一個獨立的微服務應用,用來連線設定伺服器併爲用戶端提供獲取設定資訊,加密,解密資訊等存取介面。
用戶端則是通過指定的設定中心來管理應用資源,以及與業務相關的設定內容,並在啓動的時候從設定中心獲取和載入設定資訊。設定伺服器預設採用git來儲存設定資訊,這樣就有助於對環境設定進行版本管理。並且可用通過git用戶端工具來方便的管理和存取設定內容。
spring cloud config 分佈式設定中心能幹嘛?
由於spring cloud config 預設使用git來儲存組態檔 (也有其他方式,比如自持SVN 和本地檔案),但是最推薦的還是git ,而且使用的是 http / https 存取的形式。
新建springcloud-config-server-3344模組匯入pom.xml依賴
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--config-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
resource下建立application.yml組態檔,Spring Cloud Config伺服器從git儲存庫(必須提供)爲遠端用戶端提供設定:
server:
port: 3344
spring:
application:
name: springcloud-config-server
# 連線碼雲遠端倉庫
cloud:
config:
server:
git:
#注意是https的而不是ssh
uri: https://gitee.com/cao_shi_peng/springcloud-config.git
# 通過 config-server可以連線到git,存取其中的資源以及設定~
# 不加這個設定會報Cannot execute request on any known server 這個錯:連線Eureka伺服器端地址不對
# 或者直接註釋掉eureka依賴 這裏暫時用不到eureka
eureka:
client:
register-with-eureka: false
fetch-registry: false
主啓動類
@EnableConfigServer //開啓spring cloud config server服務
@SpringBootApplication
public class Config_server_3344 {
public static void main(String[] args) {
SpringApplication.run(Config_server_3344.class,args);
}
}
將本地git倉庫springcloud-config資料夾下新建的application.yml提交到github倉庫:
定位資源的預設策略是克隆一個git倉庫(在spring.cloud.config.server.git.uri),並使用它來初始化一個迷你SpringApplication。小應用程式的Environment用於列舉屬性源並通過JSON端點發布。
HTTP服務具有以下格式的資源:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
其中「應用程式」作爲SpringApplication
中的spring.config.name
注入(即常規的Spring Boot應用程式中通常是「應用程式」),「組態檔」是活動組態檔(或逗號分隔列表的屬性),「label」是可選的git標籤(預設爲「master」)。
測試存取http://localhost:3344/application-dev.yml
測試存取 http://localhost:3344/application/test/master
如果測試存取不存在的設定則不顯示 如:http://localhost:3344/master/application-aaa.yml
將本地git倉庫springcloud-config資料夾下新建的config-client.yml提交到github倉庫:
將本地git倉庫springcloud-config資料夾下新建的config-client.yml提交到github倉庫:
新建一個springcloud-config-client-3355模組,並匯入依賴
<!--config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-start
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
pendencies>
resources下建立application.yml和bootstrap.yml組態檔
bootstrap.yml是系統級別的設定
# 系統級別的設定
spring:
cloud:
config:
name: config-client # 需要從git上讀取的資源名稱,不要後綴
profile: dev
label: master
uri: http://localhost:3344
application.yml是使用者級別的設定
# 使用者級別的設定
spring:
application:
name: springcloud-config-client
建立controller包下的ConfigClientController.java用於測試
@RestController
public class ConfigClientController {
@Value("${spring.application.name}")
private String applicationName; //獲取微服務名稱
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaServer; //獲取Eureka服務
@Value("${server.port}")
private String port; //獲取伺服器端的埠號
@RequestMapping("/config")
public String getConfig(){
return "applicationName:"+applicationName +
"eurekaServer:"+eurekaServer +
"port:"+port;
}
}
主啓動類
@SpringBootApplication
public class ConfigClient {
public static void main(String[] args) {
SpringApplication.run(ConfigClient.class,args);
}
}
測試:
啓動伺服器端Config_server_3344 再啓動用戶端ConfigClient
存取:http://localhost:8201/config/
本地新建config-dept.yml和config-eureka.yml並提交到github
新建springcloud-config-eureka-7001模組,並將原來的springcloud-eureka-7001模組下的內容拷貝的該模組。
1.清空該模組的application.yml設定,並新建bootstrap.yml連線遠端設定
spring:
cloud:
config:
name: config-eureka # 倉庫中的組態檔名稱
label: master
profile: dev
uri: http://localhost:3344
2.在pom.xml中新增spring cloud config依賴
<!--config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
3.主啓動類
@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer 伺服器端的啓動類,可以接受別人註冊進來~
public class ConfigEurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(ConfigEurekaServer_7001.class,args);
}
}
4.測試
第一步:啓動 Config_Server_3344,並存取 http://localhost:3344/master/config-eureka-dev.yml 測試
第二步:啓動ConfigEurekaServer_7001,存取 http://localhost:7001/ 測試
顯示上圖則成功
新建springcloud-config-dept-8001模組並拷貝springcloud-provider-dept-8001的內容
同理匯入spring cloud config依賴、清空application.yml 、新建bootstrap.yml組態檔並設定
spring:
cloud:
config:
name: config-dept
label: master
profile: dev
uri: http://localhost:3344
主啓動類
@SpringBootApplication
@EnableEurekaClient //在服務啓動後自動註冊到Eureka中!
@EnableDiscoveryClient //服務發現~
@EnableCircuitBreaker //
public class ConfigDeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(ConfigDeptProvider_8001.class,args);
}
//增加一個 Servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}