触发降级
商品服務(wù)獲取商品信息,那一塊的代碼拿出來(lái)再研究一下,這里有一個(gè)調(diào)用商品服務(wù),為了方便研究呢,我們把它拎出來(lái),重新寫一個(gè)接口來(lái)觀察,這里之后會(huì)用到Hystrix組件,所以這里起名叫HystrxiController,這里調(diào)用的是獲取商品列表,為了讓大家更好地理解,Hystrix這個(gè)組件,我們先不用Feign組件來(lái)調(diào)用,這里我們還是采用RestTemplate,獲取商品列表,之后再把它改成Feign+Hystrix搭配,調(diào)用的是哪個(gè)接口呢,如果啟動(dòng)的話會(huì)是8005,我們先訪問(wèn)一下,很多人遇到的是404問(wèn)題,結(jié)果不知道怎么辦了,我們先訪問(wèn)一下看地址對(duì)不對(duì)http://127.0.0.1:7900/product/listForOrder第二個(gè)參數(shù)是請(qǐng)求的入?yún)?這里傳的是一個(gè)String的list,我們傳一個(gè)productId,第三個(gè)參數(shù)是返回的類型,我們直接讓他返回String就好了,大家這個(gè)地方理解吧,雖然這里定義的是ProductList,但是實(shí)際上HTTP請(qǐng)求,實(shí)際上就是字符,就是String,只不過(guò)我們用Feign,用這個(gè)對(duì)象來(lái)接收的時(shí)候,我們這里簡(jiǎn)單一些可以用String,我們來(lái)測(cè)試一下@GetMapping("/getProductInfoList")
public String getProductInfoList(){RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:7900/product/listForOrder", Arrays.asList("157875196366160022"),String.class);}注意到目前為止,我們只是用RestTemplate去調(diào)一下這個(gè)接口,看能不能調(diào)的通,還沒(méi)有用Hystrix這個(gè)組件,端口是8010,localhost:8010/getProductInfoListhttp://127.0.0.1:7900/product/listForOrder我把product服務(wù)給停掉,就變成了500,這里顯示的是連接被拒絕I/O error on POST request for "http://127.0.0.1:7900/product/listForOrder": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect因?yàn)橐呀?jīng)關(guān)掉了,那么我們現(xiàn)在就來(lái)用Hystrix這個(gè)組件,達(dá)到服務(wù)降級(jí),用法也很簡(jiǎn)單,第一步引入依賴<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>第二步在啟動(dòng)類上加一個(gè)注解,@EnableCircuitBreaker,大家有沒(méi)有發(fā)現(xiàn)多了好多個(gè)注解,你看這里填了一大堆注解@SpringBootApplication
//@EnableRabbit
@EnableEurekaClient
@EnableCircuitBreaker
public class OrderApplication {public static void main(String[] args) {// Spring應(yīng)用啟動(dòng)起來(lái)SpringApplication.run(OrderApplication.class,args);}}我們?cè)賮?lái)看一個(gè)注解@SpringCloudApplication,跟@SpringBootApplication很像,我們點(diǎn)進(jìn)去看一下,看看他里面包含了什么/*** @author Spencer Gibb*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}是不是就包含了這三個(gè),SpringBoot,Discovery,CircuitBreaker,是不是就這三個(gè),所以我們這里可以把它給替換掉,我就注釋一下,我把這三個(gè)給注釋一下,讓大家知道一下,以后如果你要用這三個(gè)的話,其實(shí)你可以更簡(jiǎn)單的用這一個(gè)注解,加了依賴,啟動(dòng)類上也加了注解//@SpringBootApplication
//@EnableRabbit
//@EnableEurekaClient
//@EnableCircuitBreaker
@SpringCloudApplication
public class OrderApplication {public static void main(String[] args) {// Spring應(yīng)用啟動(dòng)起來(lái)SpringApplication.run(OrderApplication.class,args);}}接下來(lái)我們加一個(gè)注解@HystrixCommand,這里面有很多字段,很多參數(shù),提供我們填,fallbackMethod里面我們就填fallback,這里面的fallback是一個(gè)方法名,所以我們來(lái)寫一下這個(gè)方法,返回值跟上面的方法一樣,返回類型都是String,返回什么呢,fallback顧名思義就是你這里面出故障了,出故障了會(huì)用到這個(gè)方法,所以我們這里給一個(gè)有好的提示,就是太擁擠了,請(qǐng)稍后再試,這個(gè)提示是不是很熟悉,你去一些網(wǎng)站,秒殺搶票的話,經(jīng)常看到這類的提示,要你稍后再試,我們現(xiàn)在再來(lái)啟動(dòng)一下@RestController
public class HystrixController {@HystrixCommand(fallbackMethod = "fallback")@GetMapping("/getProductInfoList")public String getProductInfoList(){RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:7900/product/listForOrder", Arrays.asList("157875196366160022"),String.class);}private String fallback(){return "太擁擠了,請(qǐng)稍后再試~~";}
}已經(jīng)啟動(dòng),我們來(lái)訪問(wèn)一下這個(gè)接口http://localhost:8010/getProductInfoList你看返回的信息變成太擁擠了,你看你無(wú)論怎么刷新,都變成這個(gè)提示了,這就是一個(gè)服務(wù)的降級(jí),當(dāng)對(duì)方的服務(wù),注意,order去調(diào)用商品服務(wù),當(dāng)你想調(diào)用的目標(biāo)服務(wù),這邊是作為client端,那邊是作為server端,當(dāng)server端不能正常提供服務(wù)的時(shí)候,大家有沒(méi)有發(fā)現(xiàn)一點(diǎn),就是我們之前直接訪問(wèn)這個(gè)服務(wù)的時(shí)候,他其實(shí)是有異常的,我們?cè)賮?lái)訪問(wèn)一下,大家待會(huì)可以看一下控制臺(tái),瀏覽器里面是返回500http://localhost:8010/getProductInfoList控制臺(tái)其實(shí)是拋出了異常,你看堆棧都打出來(lái)了,那么現(xiàn)在換個(gè)思路,加入現(xiàn)在不是調(diào)用目標(biāo)服務(wù),而是直接拋一個(gè)異常呢,變成太擁擠了,請(qǐng)稍后再試,這說(shuō)明什么問(wèn)題呢,降級(jí)不一定是用在這種場(chǎng)景,目標(biāo)服務(wù)不能正常提供服務(wù)了,觸發(fā)降級(jí),我們也可以用到自己服務(wù)的一個(gè)降級(jí),這就完全是我服務(wù)自己內(nèi)部做的事,你看我拋個(gè)異常就出現(xiàn)服務(wù)降級(jí)了,如果并發(fā)數(shù)太高,數(shù)據(jù)庫(kù)連接數(shù)太多了,那我就給他拋一個(gè)異常,這樣子來(lái)觸發(fā)降級(jí),這是要注意的一點(diǎn),這里我先把異常給注釋掉,我們照樣來(lái)調(diào)用目標(biāo)服務(wù)@RestController
public class HystrixController {@HystrixCommand(fallbackMethod = "fallback")@GetMapping("/getProductInfoList")public String getProductInfoList(){RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:7900/product/listForOrder", Arrays.asList("157875196366160022"),String.class);
// throw new RuntimeException("發(fā)生異常了");}private String fallback(){return "太擁擠了,請(qǐng)稍后再試~~";}
}
<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.learn</groupId><artifactId>order</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><parent><groupId>cn.learn</groupId><artifactId>microcloud02</artifactId><version>0.0.1</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><thymeleaf.version>3.0.9.RELEASE</thymeleaf.version><thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</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><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-stream-rabbit</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId></dependency></dependencies><!-- 這個(gè)插件,可以將應(yīng)用打包成一個(gè)可執(zhí)行的jar包 --><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
package com.learn.cloud.controller;import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;import javax.servlet.http.HttpServletRequest;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.learn.cloud.entity.ProductInfo;
import com.learn.cloud.service.ProductService;@RestController
@RequestMapping("/product")
public class ProductController {@Autowiredprivate ProductService productService;/*** 1. 查詢所有在架的商品*/@GetMapping("/list")@CrossOrigin(allowCredentials="true")public List<ProductInfo> list(HttpServletRequest request) {Enumeration<String> headerNames = request.getHeaderNames();while(headerNames.hasMoreElements()) {String headerName = headerNames.nextElement();String headerValue = request.getHeader(headerName);System.out.println(headerName + "========>" + headerValue);}//1. 查詢所有在架的商品List<ProductInfo> productInfoList = productService.findUpAll();return productInfoList;}@PostMapping("/listForOrder")public List<ProductInfo> listForOrder(@RequestBody List<String> productIdList){System.out.println("============"+productIdList.get(0)+"============");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}ProductInfo p = new ProductInfo();p.setProductId(productIdList.get(0));p.setProductName("皮蛋粥");List<ProductInfo> list = new ArrayList<ProductInfo>();list.add(p);return list;}
}
package com.learn.controller;import java.util.Arrays;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;@RestController
public class HystrixController {@HystrixCommand(fallbackMethod = "fallback")@GetMapping("/getProductInfoList")public String getProductInfoList(){RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:7900/product/listForOrder", Arrays.asList("157875196366160022"),String.class);
// throw new RuntimeException("發(fā)生異常了");}private String fallback(){return "太擁擠了,請(qǐng)稍后再試~~";}
}
package com.learn;import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;//@SpringBootApplication
//@EnableRabbit
//@EnableEurekaClient
//@EnableCircuitBreaker
@SpringCloudApplication
public class OrderApplication {public static void main(String[] args) {// Spring應(yīng)用啟動(dòng)起來(lái)SpringApplication.run(OrderApplication.class,args);}}
?
總結(jié)
- 上一篇: 服务容错和Hystrix
- 下一篇: 超时设置