一、SpringCloud簡介
微服務
微服務化的核心就是將傳統的一站式應用,根據業務拆分成一個一個的服務,徹底地去解耦合,每一個微服務提供單個業務功能也服務,一個服務做一件事,從技術角度看就是一種小而獨立的處理過程,類似進程概念,能夠自行單獨啟動或銷毀,擁有自己獨立的數據庫。
SpringCloud與Dubbo對比
Dubbo | SpringCloud | |
---|---|---|
服務注冊中心 | Zookeeper | Eureka |
服務調用方式 | RPC | RestAPI |
服務監控 | Dubbo-monitor | Spring Boot Admin |
斷路器 | 不完善 | Hystrix |
服務網關 | 無 | Zuul |
分布式配置 | 無 | Spring Cloud Config |
服務跟蹤 | 無 | Spring Cloud Sleuth |
消息總線 | 無 | Spring Cloud Bus |
數據流 | 無 | Spring Cloud Stream |
批量任務 | 無 | Spring Cloud Task |
最大區別:SpringCloud拋棄了Dubbo的RPC通信,采用的是基於HTTP的REST方式。 嚴格來說,這兩種方式各有優劣,雖然從一定程度上來說,后者犧牲了服務調用的性能,但也避免了上面提到的原生RPC帶來的問題。而且REST相比RPC更為靈活,服務提供方和調用方的依賴只依靠一紙契約,不存在代碼級別的強依賴,這在強調快速演化的微服務環境下,顯得更加合適。
一、Rest微服務構建
項目結構
microservicecloud // 父項目
|- microservicecloud-api // 存放公共接口、實體類。。
|- microservicecloud-provider-dept-8081 // 部門服務提供者
|- microservicecloud-consumer-dept-80 // 部門服務消費者
1、創建maven父項目
書寫pom.xml文件

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>cn.x5456</groupId> 8 <artifactId>microservicecloud</artifactId> 9 <packaging>pom</packaging> 10 <version>1.0-SNAPSHOT</version> 11 <modules> 12 <module>microservicecloud-api</module> 13 </modules> 14 15 <properties> 16 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 17 <maven.compiler.source>1.8</maven.compiler.source> 18 <maven.compiler.target>1.8</maven.compiler.target> 19 <junit.version>4.12</junit.version> 20 <log4j.version>1.2.17</log4j.version> 21 <lombok.version>1.16.18</lombok.version> 22 </properties> 23 24 <dependencyManagement> 25 <dependencies> 26 <dependency> 27 <groupId>org.springframework.cloud</groupId> 28 <artifactId>spring-cloud-dependencies</artifactId> 29 <version>Dalston.SR1</version> 30 <type>pom</type> 31 <scope>import</scope> 32 </dependency> 33 <dependency> 34 <groupId>org.springframework.boot</groupId> 35 <artifactId>spring-boot-dependencies</artifactId> 36 <version>1.5.9.RELEASE</version> 37 <type>pom</type> 38 <scope>import</scope> 39 </dependency> 40 <dependency> 41 <groupId>mysql</groupId> 42 <artifactId>mysql-connector-java</artifactId> 43 <version>5.0.4</version> 44 </dependency> 45 <dependency> 46 <groupId>com.alibaba</groupId> 47 <artifactId>druid</artifactId> 48 <version>1.0.31</version> 49 </dependency> 50 <dependency> 51 <groupId>org.mybatis.spring.boot</groupId> 52 <artifactId>mybatis-spring-boot-starter</artifactId> 53 <version>1.3.0</version> 54 </dependency> 55 <dependency> 56 <groupId>ch.qos.logback</groupId> 57 <artifactId>logback-core</artifactId> 58 <version>1.2.3</version> 59 </dependency> 60 <dependency> 61 <groupId>junit</groupId> 62 <artifactId>junit</artifactId> 63 <version>${junit.version}</version> 64 <scope>test</scope> 65 </dependency> 66 <dependency> 67 <groupId>log4j</groupId> 68 <artifactId>log4j</artifactId> 69 <version>${log4j.version}</version> 70 </dependency> 71 </dependencies> 72 </dependencyManagement> 73 74 <build> 75 <finalName>microservicecloud</finalName> 76 <resources> 77 <resource> 78 <directory>src/main/resources</directory> 79 <filtering>true</filtering> 80 </resource> 81 </resources> 82 <plugins> 83 <plugin> 84 <groupId>org.apache.maven.plugins</groupId> 85 <artifactId>maven-resources-plugin</artifactId> 86 <configuration> 87 <delimiters> 88 <delimit>$</delimit> 89 </delimiters> 90 </configuration> 91 </plugin> 92 </plugins> 93 </build> 94 95 </project>
2、創建microservicecloud-api項目
和上面一樣
1)書寫pom.xml文件

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>microservicecloud</artifactId> 7 <groupId>cn.x5456</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>microservicecloud-api</artifactId> 13 14 <dependencies><!-- 當前Module需要用到的jar包,按自己需求添加,如果父類已經包含了,可以不用寫版本號 --> 15 <dependency> 16 <groupId>org.springframework.cloud</groupId> 17 <artifactId>spring-cloud-starter-feign</artifactId> 18 </dependency> 19 <dependency> 20 <groupId>org.springframework.boot</groupId> 21 <artifactId>spring-boot-starter-data-jpa</artifactId> 22 </dependency> 23 </dependencies> 24 </project>
2)書寫實體類
// 在api中這樣寫,有一點問題 @Entity // 告訴JPA這是一個實體類(對應數據表),不是普通的javabean @Table(name = "tb_dept") // 不寫這個注解,默認為這個類的小寫作為名字 public class Dept implements Serializable { @Id // 標識這是主鍵 @GeneratedValue(strategy = GenerationType.AUTO) // 根據數據庫自動選則主鍵自增類型 private Long deptno; // 主鍵 private String dname; // 部門名稱 private String dbSource;// 來自那個數據庫,因為微服務架構可以一個服務對應一個數據庫,同一個信息被存儲到不同數據庫
3、創建microservicecloudproviderdept8081(提供者)
1)書寫pom.xml文件

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>microservicecloud</artifactId> 7 <groupId>cn.x5456</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>microservicecloud-provider-dept-8081</artifactId> 13 <dependencies> 14 <!-- 引入自己定義的api通用包,可以使用Dept部門Entity --> 15 <dependency> 16 <groupId>cn.x5456</groupId> 17 <artifactId>microservicecloud-api</artifactId> 18 <version>${project.version}</version> 19 </dependency> 20 <!-- actuator監控信息完善 --> 21 <dependency> 22 <groupId>org.springframework.boot</groupId> 23 <artifactId>spring-boot-starter-actuator</artifactId> 24 </dependency> 25 <!-- 將微服務provider側注冊進eureka --> 26 <dependency> 27 <groupId>org.springframework.cloud</groupId> 28 <artifactId>spring-cloud-starter-eureka</artifactId> 29 </dependency> 30 <dependency> 31 <groupId>org.springframework.cloud</groupId> 32 <artifactId>spring-cloud-starter-config</artifactId> 33 </dependency> 34 <dependency> 35 <groupId>junit</groupId> 36 <artifactId>junit</artifactId> 37 </dependency> 38 <!--<dependency>--> 39 <!--<groupId>mysql</groupId>--> 40 <!--<artifactId>mysql-connector-java</artifactId>--> 41 <!--</dependency>--> 42 <dependency> 43 <groupId>com.oracle</groupId> 44 <artifactId>ojdbc14</artifactId> 45 <version>10.2.0.4.0</version> 46 </dependency> 47 <dependency> 48 <groupId>com.alibaba</groupId> 49 <artifactId>druid</artifactId> 50 </dependency> 51 <dependency> 52 <groupId>ch.qos.logback</groupId> 53 <artifactId>logback-core</artifactId> 54 </dependency> 55 <dependency> 56 <groupId>org.mybatis.spring.boot</groupId> 57 <artifactId>mybatis-spring-boot-starter</artifactId> 58 </dependency> 59 <dependency> 60 <groupId>org.springframework.boot</groupId> 61 <artifactId>spring-boot-starter-jetty</artifactId> 62 </dependency> 63 <dependency> 64 <groupId>org.springframework.boot</groupId> 65 <artifactId>spring-boot-starter-web</artifactId> 66 </dependency> 67 <dependency> 68 <groupId>org.springframework.boot</groupId> 69 <artifactId>spring-boot-starter-test</artifactId> 70 </dependency> 71 <!-- 修改后立即生效,熱部署 --> 72 <dependency> 73 <groupId>org.springframework</groupId> 74 <artifactId>springloaded</artifactId> 75 </dependency> 76 <dependency> 77 <groupId>org.springframework.boot</groupId> 78 <artifactId>spring-boot-devtools</artifactId> 79 </dependency> 80 </dependencies> 81 82 </project>
2)目錄結構
DeptProvider8081_App
@SpringBootApplication public class DeptProvider8001_App { public static void main(String[] args) { SpringApplication.run(DeptProvider8001_App.class, args); } }
controller
@RestController public class DeptController { @Autowired private DeptService service; @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public Dept add(Dept dept){ return service.addDept(dept); } @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) public Dept get(@PathVariable("id") Long id) { return service.findById(id); } @RequestMapping(value = "/dept/list", method = RequestMethod.GET) public List<Dept> list(){ return service.findAll(); } }
service
@Service public class DeptServiceImpl implements DeptService { @Resource private DeptRepository deptRepository; @Override public Dept addDept(Dept dept) { return deptRepository.save(dept); } @Override public Dept findById(Long id) { return deptRepository.findOne(id); } @Override public List<Dept> findAll() { return deptRepository.findAll(); } }
repository
public interface DeptRepository extends JpaRepository<Dept,Long> { }
3)書寫配置文件
spring: application: name: microservicecloud-dept datasource: url: jdbc:oracle:thin:@127.0.0.1:1521:orcl username: scott password: tiger driver-class-name: oracle.jdbc.OracleDriver jpa: hibernate: # 更新或創建數據表 ddl-auto: update # 控制台打印sql show-sql: true server: context-path: /DeptProvider8001_App port: 8001
4、創建microservicecloudconsumerdept80
1)書寫pom.xml文件

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>microservicecloud</artifactId> 7 <groupId>cn.x5456</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>microservicecloud-consumer-dept-80</artifactId> 13 14 <dependencies> 15 <dependency><!-- 自己定義的api --> 16 <groupId>cn.x5456</groupId> 17 <artifactId>microservicecloud-api</artifactId> 18 <version>${project.version}</version> 19 </dependency> 20 <!-- Ribbon相關 --> 21 <dependency> 22 <groupId>org.springframework.cloud</groupId> 23 <artifactId>spring-cloud-starter-eureka</artifactId> 24 </dependency> 25 <dependency> 26 <groupId>org.springframework.cloud</groupId> 27 <artifactId>spring-cloud-starter-ribbon</artifactId> 28 </dependency> 29 <dependency> 30 <groupId>org.springframework.cloud</groupId> 31 <artifactId>spring-cloud-starter-config</artifactId> 32 </dependency> 33 <dependency> 34 <groupId>org.springframework.boot</groupId> 35 <artifactId>spring-boot-starter-web</artifactId> 36 </dependency> 37 <!-- 修改后立即生效,熱部署 --> 38 <dependency> 39 <groupId>org.springframework</groupId> 40 <artifactId>springloaded</artifactId> 41 </dependency> 42 <dependency> 43 <groupId>org.springframework.boot</groupId> 44 <artifactId>spring-boot-devtools</artifactId> 45 </dependency> 46 <dependency> 47 <groupId>com.oracle</groupId> 48 <artifactId>ojdbc14</artifactId> 49 <version>10.2.0.4.0</version> 50 </dependency> 51 </dependencies> 52 53 </project>
2)目錄結構
DeptConsumer80_App
@SpringBootApplication public class DeptConsumer80_App { public static void main(String[] args) { SpringApplication.run(DeptConsumer80_App.class, args); } }
書寫配置類
@Configuration public class ConfigBean //boot -->spring applicationContext.xml --- @Configuration配置 ConfigBean = applicationContext.xml{ @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
controller
@RestController public class DeptController_Consumer{ private static final String REST_URL_PREFIX = "http://localhost:8001/DeptProvider8001_App"; /** * 使用 使用restTemplate訪問restful接口非常的簡單粗暴無腦。 (url, requestMap, * ResponseBean.class)這三個參數分別代表 REST請求地址、請求參數、HTTP響應轉換被轉換成的對象類型。 */ @Autowired private RestTemplate restTemplate; @RequestMapping(value = "/consumer/dept/add") public boolean add(Dept dept) { return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class); } @RequestMapping(value = "/consumer/dept/get/{id}") public Dept get(@PathVariable("id") Long id) { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class); } @RequestMapping(value = "/consumer/dept/list") public List<Dept> list() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class); } }
3)配置文件
### 理論上這部分不應該有 ### spring: datasource: url: jdbc:oracle:thin:@127.0.0.1:1521:orcl username: scott password: tiger driver-class-name: oracle.jdbc.OracleDriver jpa: hibernate: # 更新或創建數據表 ddl-auto: update # 控制台打印sql show-sql: true ################## server: port: 80 context-path: /DeptConsumer80_App
二、Eureka
簡介
Eureka是Spring Cloud Netflix的一個子模塊,也是核心模塊之一。用於雲端服務發現,一個基於REST的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。服務的注冊與發現對應微服務架構來說是非常重要的,有了服務的發現與注冊,只需要使用服務標識符,就可以訪問到服務,而不需要修改服務調用的配置文件了。
其功能類似與dubbo的注冊中心(zookeeper)。
基本架構
SpringCloud封裝了Netflix公司開發的Eureka模塊來實現服務的注冊與發現。
Eureka采用了C-S的設計架構。Eureka Server作為服務注冊功能的服務器,它是服務的注冊中心。而系統中其他的微服務,使用Eureka的客戶端連接到Eureka Server並維持心跳連接,這樣系統的維護人員就可以通過Eureka Server來監控系統中各個微服務是否正常運行。SpringCloud的一些其他模塊(Zuul)就可以通過Eureka來發現系統中的其他微服務,並執行相關的邏輯。
Eureka包含兩個組件:Eureka Server和Eureka Client
Eureka Server提供服務注冊服務,在各個節點啟動后,會在Eureka Server中進行注冊,這樣EurekaServer中的服務注冊表中將會存儲所有可用服務節點的信息,服務階段的信息可以在界面中直觀的看到。
EurekaClient是一個Java客戶端,用於簡化EurekaServer的交互,客戶端同時也具備一個內置的、使用輪詢負載算法的負載均衡器。在應用啟動后,將會EurekaServer發送心跳(默認周期是30s)。如果EurekaServer在多個心跳周期內沒有接收到某個節點的心跳,EurekaServer將會從服務注冊表中吧這個服務節點移除(默認30s)。
SpringCloud中三大角色
-
EurekaServer:提供服務的注冊和發現
-
Server Provider服務提供方將自身服務注冊到Eureka,從而使服務消費方可以找到
-
Service Consumer服務消費方從Eureka獲取注冊服務列表,從而可以消費服務
默認情況下,如果EurekaServer在一定時間內沒有接收到某個微服務實例的心跳,Eureka Server將會注銷該實例(默認90秒)。但是當網絡分區發生故障時,微服務與EurekaServer之間無法正常通信,以上行為可能變得非常危險了——因為微服務本身其實是健康的,此時不應該注銷這個微服務。Eureka通過“自我保護模式”來解決這個問題——當EurekaServer節點在短時間內丟失過多客戶端時(可能網絡分區發生故障),那么這個節點就會進入自我保護模式。一旦進入改模式,EurekaServer就會保護服務注冊表中的信息,不再刪除服務注冊表中的數據(也就是不會注銷任何微服務)。當網絡故障恢復后,改Eureka節點會自動退出自我保護模式。
綜上自我保護模式是一種應對網絡異常的安全保護措施。他的架構哲學是寧可保留所有微服務(不管它健不健康都會保留),也不盲目注銷任何微服務。使用自我保護模式,可以讓Eureka集群更加健壯、穩定。
作為服務注冊中心,Eureka比Zookeeper好在哪
分布式系統的CAP理論
● 一致性(C):在分布式系統中的所有數據備份,在同一時刻是否同樣的值。(等同於所有節點訪問同一份最新的數據副本)
● 可用性(A):在集群中一部分節點故障后,集群整體是否還能響應客戶端的讀寫請求。(對數據更新具備高可用性)
● 分區容錯性(P):以實際效果而言,分區相當於對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味着發生了分區的情況,必須就當前操作在C和A之間做出選擇。
Zookeeper保證的是CP
當向注冊中心查詢服務列表時,我們可以容忍注冊中心返回的是幾分鍾前的注冊信息,但不能接受直接down掉不可用。也就是說,服務注冊功能對可用性的要求要高於一致性。但是Zookeeper會出現這樣一種情況,當master節點因為網絡故障與其他節點失去聯系時,剩余節點會重新進行leader選舉。問題在於,選舉leader的時間太長,30 ~ 120s,且選舉期間整個zk集群都是不可用的,這就導致在選舉期間注冊服務癱瘓。在雲部署的環境下,因網絡問題使得zk集群失去master節點是較大概率會發生的事,雖然服務能夠恢復,但是漫長的選舉時間導致的注冊長期不可用是不能容忍的。
Eureka保證的是AP
Eureka看明白了這一點,因此在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作 ,剩余的節點依然可以提供注冊和查詢服務。而Eureka的客戶端在向某個Eureka注冊或時如果發現連接失敗,則會自動切換至其它節點,只要有一台Eureka還在,就能保證注冊服務可用(保證可用性),只不過查到的信息可能不是最新的(不保證強一致性)。除此之外,Eureka還有一種自我保護機制,如果在15分祌內超過85%的節點都沒有正常的心跳,那么Eureka就認為客戶端與注冊中心出現了網絡故障,此時會出現以下幾種情況:
-
Eureka不再從注冊列表中移除因為長時間沒收到心跳而應該過期的服務
-
Eureka仍然能夠接受新服務的注冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點依然可用)
-
當網絡穩定時,當前實例新的注冊信息會被同步到其它節點中
因此,Eureka可以很好的應對因網絡故障導致部分節點失去聯系的情況,而不會像Zookeeper那樣是整個注冊服務癱瘓。
項目中引入E
1、新建Eureka項目microservicecloud-eureka-7001
1)新建項目
2)目錄結構
MicroservicecloudEureka7001Application
@SpringBootApplication @EnableEurekaServer // 代表eureka服務端 public class MicroservicecloudEureka7001Application { public static void main(String[] args) { SpringApplication.run(MicroservicecloudEureka7001Application.class, args); } }
書寫配置文件
# 端口號 server.port=7001 # 主機名 eureka.instance.hostname=localhost # 是否向服務注冊中心注冊自己 eureka.client.register-with-eureka=false # 是否檢索服務,false表示自己就是注冊中心,不需要去檢索服務 eureka.client.fetch-registry=false # 服務注冊中心的配置內容,指定服務注冊中心的位置 eureka.client.service-url.defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
2、修改提供者和消費者部分配置
1)修改服務提供者與消費者的主方法
@SpringBootApplication
@EnableEurekaClient // eureka客戶端
public class DeptProvider8001_App {
public static void main(String[] args) {
SpringApplication.run(DeptProvider8001_App.class, args);
}
}
2)為服務提供者與消費者配置文件中添加配置
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
3)還要在restTemplate上添加負載均衡注解,客戶端才可以調用
此時url可以改為提供者在Eureka中注冊的名字
Eureka集群的搭建
1、再創建2個Eureka項目
2、修改系統hosts文件的映射(為了防止名字沖突)
3、書寫配置文件
4、修改服務提供者的配置文件
將這個服務注冊到每一個eureka上
5、成功頁面
三、Ribbon
簡介
Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具。
Ribbon是Netflix發布的開源項目,主要功能是提供客戶端的軟件負載衡算法,將Netflix的中間層服務連接在一起。 Ribbon客戶端組件提供一系列完善的配置項如連接超時,重試等。簡單的說,就是在配置文件中列出Load Balancer (負載均衡)后面所有的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機連接等)去連接這些機器。我們也很容易使用Ribbon實現自定義的負載均衡算法。
基本架構
Ribbon在工作時分成兩步
第一步先選擇EurekaServer,他優先選則在同一個區域內負載較少的server
第二步在根據用戶指定的策略,從server渠道的服務注冊列表中選則一個地址。
Ribbon的irule組件
Ribbon默認是采用輪詢的方式進行負載均衡,我們可以使用irule進行指定。
Ribbon的使用
首先要在(消費者)pom.xml文件中引入jar包
<!-- Ribbon相關 -->
<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.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
之前為了能夠使用微服務名稱來調用服務時,我們已經使用過ribbon了,沒錯就是這個:
Robbon默認使用的是輪詢算法,總共有以下幾種算法:
可以使用以下方法進行修改算法
四、
簡介
Feign是一個聲明式WebService客戶端。使得編寫Web服務客戶端變得非常容易,我們只需要創建一個接口,然后在上面添加注解即可。
Feign旨在使編寫JavaHttp客戶端變得更容易。前面在使用Ribbon+RestTemplate時,利用RestTemplate對http請求的封裝處理,形成了一套模板化的調用方法,但是在實際開發中,由於對服務依賴的調用可能不止一處,往往一個接口會被多處調用,所以通常都會針對每個微服務自行封裝一些客戶端類來包裝這些依賴服努的調用。所以,Feign在此基礎上做了進一步封裝,由他來幫助我們定義和實現依賴服務接口的定義。在 Feign的實現下,我們只需創建一個接口並使用注解的方式來配置它,即可完成對服務提供方的接口綁定,簡化了使用Spring cloud Ribbon時,自動封裝服務調用客戶端的開發量。
Feign集成了Ribbon,使用它來進行負載均衡。
1、創建消費者microservicecloud-consumer-dept-feign
pom.xml導入相應依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
2、在microservicecloud-api中添加接口
@FeignClient(value = "MICROSERVICECLOUD-DEPT/DeptConsumerDeptFeign_App") // 這個是我們要調用的提供者在eureka中注冊的名字 public interface DeptClientService { @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) // 要請求 提供者 的url public Dept get(@PathVariable("id") long id); @RequestMapping(value = "/dept/list", method = RequestMethod.GET) public List<Dept> list(); @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public boolean add(Dept dept); }
3、microservicecloudconsumerdeptfeign中的一些操作
DeptConsumerDeptFeign_App
@SpringBootApplication @EnableEurekaClient @EnableFeignClients(basePackages= {"cn.x5456.microservicecloud"}) // 掃描所有Feign的接口 @ComponentScan("cn.x5456.springcloud") // 掃描我們調用的controller public class DeptConsumerDeptFeign_App { public static void main(String[] args) { SpringApplication.run(DeptConsumerDeptFeign_App.class, args); } }
DeptController_Consumer(變得和我們面向接口編程一樣了)
@RestController public class DeptController_Consumer { @Autowired private DeptClientService service; @RequestMapping(value = "/consumer/dept/get/{id}") public Dept get(@PathVariable("id") Long id) { return this.service.get(id); } @RequestMapping(value = "/consumer/dept/list") public List<Dept> list() { return this.service.list(); } @RequestMapping(value = "/consumer/dept/add") public Object add(Dept dept) { return this.service.add(dept); } }
配置文件和以前一樣
五、
簡介
1、概念
一般處某個服務故障異常引起,類似現實世界中的“保險絲“,當某個異常條件被觸發,直接熔斷整個服務,而不是一直等到此服務超時。
2、使用
1)(提供者端)導入依賴
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
2)在需要進行熔斷處理的方法上添加注解,書寫熔斷方法
@RestController public class DeptController { @Autowired private DeptService service = null; @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) //一旦調用服務方法失敗並拋出了錯誤信息后,會自動調用@HystrixCommand標注好的fallbackMethod調用類中的指定方法 @HystrixCommand(fallbackMethod = "processHystrix_Get") public Dept get(@PathVariable("id") Long id) { Dept dept = this.service.get(id); if (null == dept) { throw new RuntimeException("該ID:" + id + "沒有沒有對應的信息"); } return dept; } public Dept processHystrix_Get(@PathVariable("id") Long id) { return new Dept().setDeptno(id).setDname("該ID:" + id + "沒有沒有對應的信息,null--@HystrixCommand") .setDb_source("no this database in MySQL"); } }
3)在主方法上添加@EnableCircuitBreaker注解
@SpringBootApplication @EnableEurekaClient //本服務啟動后會自動注冊進eureka服務中 @EnableCircuitBreaker//對hystrixR熔斷機制的支持 public class DeptProvider8001_Hystrix_App { public static void main(String[] args) { SpringApplication.run(DeptProvider8001_Hystrix_App.class, args); } }
3、問題
- 沒有實現解耦的思想
- 方法膨脹(每有一個方法就要有一個對應的斷路器方法)
- 服務降級
服務降級
1、概念
降級,一般是從整體負荷考慮。就是當某個服務熔斷之后,服務器將不再被調用,此時客戶端可以自己准備一個本地的fallback回調,返回—個缺省值。這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強。
2、使用
1)在microservicecloud-api項目,根據剛剛寫的DeptClientService接口新建一個實現了FallbackFactory接口的類DeptClientServiceFallbackFactory
@Component // 不要忘記添加 public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public Dept get(long id) { Dept dept = new Dept(); dept.setDname("yyy"); return dept; } @Override public List<Dept> list() { return null; } @Override public boolean add(Dept dept) { return false; } }; } }
2)為DeptClientService的注解中添加參數
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
3)在消費者端的配置文件中添加下面配置:
feign:
hystrix:
enabled: true
4)測試
- 啟動enreka,啟動提供者,啟動消費者
- 故意關閉服務提供者
- 再次進行訪問,查看效果
六、Zuul(路由網關)
簡介
Zuul包含了對請求的路由和過濾兩個最主要的功能: 其中路由功能負責將外部請求轉發到具體的微服務實例上,是實現外部訪問統一入口的基礎而過濾器功能則負責對請求的處理過程進行干預,是實現請求校驗、服務聚合等功能的基礎。
Zuul和Eureka進行整合,將Zuul自身注冊為Eureka服務治理下的應用,同時從Eureka中獲得其他微服務的消息,也即以后的訪問微服務都是通過Zuul跳轉后獲得。