公衆號: java樂園java
在微服務架構中,根據業務需求拆分紅一個個的微小服務,而後服務與服務之間能夠相互RPC遠程調用。在Spring Cloud可使用RestTemplate+Ribbon或者Feign來進行RPC遠程調用。爲了保證服務高可用性,單個服務一般會進行集羣部署。因爲網絡緣由或者自身的緣由,服務並不能保證百分之一百可用,若是服務方出現問題,調用這個服務就會出現線程阻塞,此時如有出現大量請求,致使服務方癱瘓。這時斷路器就派上用場了。git
當對某個服務的調用的不可用達到一個閥值(Hystric 默認是5秒20次) 斷路器將會被自動被打開。斷路打開後, fallback方法能夠直接返回一個預先設置的固定值。github
一、 新建項目sc-eureka-client-consumer-ribbon-hystrix,對應的pom.xml文件web
<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>spring-cloud</groupId> <artifactId>sc-eureka-client-consumer-ribbon</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>sc-eureka-client-consumer-ribbon</name> <url>http://maven.apache.org</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.5.RELEASE</version> </dependency> --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.5.RELEASE</version> </dependency> --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.0.1.RELEASE</version> </dependency> </dependencies> </project>
備註:spring-cloud-starter-hystrix已經在spring cloud 2.x標註成過時。推薦使用spring-cloud-starter-netflix-hystrixspring
二、 新建spring boot 啓動類ConsumerApplication.java數據庫
package sc.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; @SpringBootApplication @EnableEurekaClient @EnableHystrix public class ConsumerHystrixApplication { public static void main(String[] args) { SpringApplication.run(ConsumerHystrixApplication.class, args); } }
能夠看出這個啓動類只是《服務發現&服務消費者Ribbon》的啓動類添加多了一個註解EnableHystrix(啓動斷路器)apache
三、 編寫服務類,並添加斷路器註解bootstrap
package sc.consumer.service.impl; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.github.andrewoma.dexx.collection.ArrayList; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import sc.consumer.model.User; import sc.consumer.service.UserService; @Service public class UserServiceImpl implements UserService{ @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "getUserError") @Override public Map<String, Object> getUser(Long id) { return restTemplate.getForObject("http://sc-eureka-client-provider:8200/user/getUser/{1}", Map.class, id); } public Map<String, Object> getUserError(Long id){ Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "000000"); map.put("msg", "ok"); User u = new User(); u.setId(-1L); u.setUserName("failName"); map.put("body", u); return map; } @HystrixCommand(fallbackMethod = "listUserError") @Override public Map<String, Object> listUser() { return restTemplate.getForObject("http://sc-eureka-client-provider:8200/user/listUser", Map.class); } public Map<String, Object> listUserError(){ Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "000000"); map.put("msg", "ok"); map.put("body", new ArrayList<User>()); return map; } @HystrixCommand(fallbackMethod = "addUserError") @Override public Map<String, Object> addUser(User user) { return restTemplate.postForObject("http://sc-eureka-client-provider:8200/user/addUser", user, Map.class); } public Map<String, Object> addUserError(User user){ Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "000000"); map.put("msg", "ok"); map.put("body", 0); return map; } @HystrixCommand(fallbackMethod = "updateUserError") @Override public Map<String, Object> updateUser(User user) { restTemplate.put("http://sc-eureka-client-provider:8200/user/updateUser",user); Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "000000"); map.put("msg", "ok"); return map; } public Map<String, Object> updateUserError(User user){ Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "000000"); map.put("msg", "ok"); map.put("body", 0); return map; } @HystrixCommand(fallbackMethod = "deleteUserError") @Override public Map<String, Object> deleteUser(Long id) { restTemplate.delete("http://sc-eureka-client-provider:8200/user/deleteUser/{id}", id); Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "000000"); map.put("msg", "ok"); return map; } public Map<String, Object> deleteUserError(Long id){ Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "000000"); map.put("msg", "ok"); map.put("body", 0); return map; } }
添加HystrixCommand註解,對應的參數fallbackMethod值爲當方式服務方沒法調用時,返回預設值得方法名。網絡
四、 新建配置文件bootstrap.yml和application.yml
bootstrap.yml架構
server: port: 5600 application.yml spring: application: name: sc-eureka-client-consumer-ribbon-hystrix eureka: instance: hostname: 127.0.0.1 client: #因爲該應用爲註冊中心,因此設置爲false,表明不向註冊中心註冊本身 registerWithEureka: true #因爲註冊中心的職責就是維護服務實例,它並不須要去檢索服務,因此也設置爲false fetchRegistry: true serviceUrl: defaultZone: http://127.0.0.1:5001/eureka/
五、 其餘項目文件參加下圖
六、 分別啓動註冊中心sc-eureka-server和服務提供者sc-eureka-client-provider
七、 啓動sc-eureka-client-consumer-ribbon-hystrix,並驗證是否啓動成功
方式一:查看日誌
方式二:查看註冊中心是否註冊成功
八、 驗證斷路器是否起做用
(1) 服務提供者正常時訪問:
http://127.0.0.1:5600/cli/user/getUser/4
正常返回數據庫裏的數據
(2) 服務提供者關閉時訪問:
http://127.0.0.1:5600/cli/user/getUser/4
對比兩個返回的數據,能夠看出服務提供者關閉時,返回的數據是在程序寫死的數據,以下圖:
其餘方法能夠自行按照以上方式進行驗證。