Spring Cloud學習筆記24——天氣預報系統微服務實現熔斷機制
阿新 • • 發佈:2018-11-16
建立專案
以之前的msa-weather-report-eureka-feign-gateway
為藍本,建立msa-weather-report-eureka-feign-gateway-hystrix
專案
修改build.gradle
配置,新增Hystrix
依賴:
//依賴關係
dependencies {
//該依賴用於編譯階段
compile('org.springframework.boot:spring-boot-starter-web')
//新增Spring Boot Thymeleaf Starter的依賴
compile('org.springframework.boot:spring-boot-starter-thymeleaf' )
//Eureka Client
compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
//Feign
compile('org.springframework.cloud:spring-cloud-starter-openfeign:2.0.0.M3')
//Hystrix
compile('org.springframework.cloud:spring-cloud-starter-netflix-hystrix')
//該依賴用於測試階段
testCompile('org.springframework.boot:spring-boot-starter-test')
}
修改com.study.spring.cloud.weather
包下的Application
類,加入@EnableCircuitBreaker
註解:
package com.study.spring.cloud.weather;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
/*
* @SpringBootApplication註解宣告Spring Boot應用
* 作用等同於@Configuration, @EnableAutoConfiguration, @ComponentScan,
* 簡化Spring配置
*/
@SpringBootApplication
//啟用可發現的客戶端
@EnableDiscoveryClient
//啟用Feign
@EnableFeignClients
//啟用Hystrix
@EnableCircuitBreaker
//Application類一定要處於整個工程的根目錄下,這樣它才能根據配置去掃描子節點下的Spring的Bean
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
在com.study.spring.cloud.weather.service
包下新建類DataClientFallback
:
package com.study.spring.cloud.weather.service;
import com.study.spring.cloud.weather.vo.City;
import com.study.spring.cloud.weather.vo.WeatherResponse;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
//宣告為Bean
@Component
public class DataClientFallback implements DataClient {
@Override
public List<City> listCity() throws Exception {
List<City> cityList=null;
cityList=new ArrayList<>();
City city=new City();
city.setCityId("101020100");
city.setCityName("上海");
cityList.add(city);
city=new City();
city.setCityId("101010100");
city.setCityName("北京");
cityList.add(city);
return cityList;
}
@Override
public WeatherResponse getDataByCityId(String cityId) {
return null;
}
}
修改com.study.spring.cloud.weather.service
包下的WeatherReportServiceImpl
類:
package com.study.spring.cloud.weather.service;
import com.study.spring.cloud.weather.vo.Weather;
import com.study.spring.cloud.weather.vo.WeatherResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class WeatherReportServiceImpl implements WeatherReportService {
@Autowired
private DataClient dataClient;
@Override
public Weather getDataByCityId(String cityId) {
//由天氣資料API微服務來提供資料
WeatherResponse resp=dataClient.getDataByCityId(cityId);
Weather data=null;
if(resp!=null){
data=resp.getData();
}
return data;
}
}
修改com.study.spring.cloud.weather.service
包下的DataClient
介面:
package com.study.spring.cloud.weather.service;
import com.study.spring.cloud.weather.vo.City;
import com.study.spring.cloud.weather.vo.WeatherResponse;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@FeignClient(name = "msa-weather-eureka-client-zuul",fallback = DataClientFallback.class)
public interface DataClient {
//獲取城市列表
@GetMapping("/city/cities")
List<City> listCity() throws Exception;
//根據城市id查詢天氣資料
@GetMapping("/data/weather/cityId/{cityId}")
WeatherResponse getDataByCityId(@PathVariable("cityId") String cityId);
}
修改前端頁面report.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>天氣預報</title>
</head>
<body>
<div class="container">
<div class="row">
<h3 th:text="${reportModel.title}">天氣</h3>
<select class="custom-select" id="selectCityId">
<option th:each="city : ${reportModel.cityList}"
th:value="${city.cityId}" th:text="${city.cityName}"
th:selected="${city.cityId eq reportModel.cityId}"></option>
</select>
</div>
<div th:if="${reportModel.report}!=null">
<div class="row">
<h1 class="text-success" th:text="${reportModel.report.city}">城市名稱</h1>
</div>
<div class="row">
<p>
空氣質量指數:<span th:text="${reportModel.report.aqi}"></span>
</p>
</div>
<div class="row">
<p>
當前溫度:<span th:text="${reportModel.report.wendu}"></span>
</p>
</div>
<div class="row">
<p>
溫馨提示:<span th:text="${reportModel.report.ganmao}"></span>
</p>
</div>
<div class="row">
<div class="card border-info" th:each="forecast : ${reportModel.report.forecast}">
<div class="card-body text-info">
<p class="card-text" th:text="${forecast.date}">日期</p>
<p class="card-text" th:text="${forecast.type}">天氣型別</p>
<p class="card-text" th:text="${forecast.high}">最高溫度</p>
<p class="card-text" th:text="${forecast.low}">最低溫度</p>
<p class="card-text" th:text="${forecast.fengxiang}">風向</p>
</div>
</div>
</div>
</div>
<div th:if="${reportModel.report}==null">
<div class="row">
<p>
天氣資料API微服務暫不可用!
</p>
</div>
</div>
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<!-- Optional JavaScript -->
<script type="text/javascript" th:src="@{/js/weather/report.js}"></script>
</body>
</html>
修改application.properties
配置檔案:
#熱部署靜態檔案
spring.thymeleaf.cache=false
#應用名稱
spring.application.name=msa-weather-report-eureka-feign-gateway-hystrix
#註冊伺服器的URL
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
#請求服務時的超時時間
feign.client.config.feignName.connect-timeout=5000
#讀資料時的超時時間
feign.client.config.feignName.read-timeout=5000
#在feign客戶端中啟用斷路器功能
feign.hystrix.enabled=true
執行
- 啟動
Redis
- 在
IDE
上執行micro-weather-eureka-server
- 通過命令列指定
8081
和8082
埠執行msa-weather-collection-eureka-feign
- 通過命令列指定
8083
和8084
埠執行msa-weather-data-eureka
- 通過命令列指定
8085
和8086
埠執行msa-weather-city-eureka
- 通過命令列指定
8087
和8088
埠執行msa-weather-report-eureka-feign-gateway-hystrix
- 通過命令列指定
8089
埠執行msa-weather-eureka-client-zuul
訪問http://localhost:8761
頁面,可以看到Eureka
的管理頁面:
訪問http://localhost:8088/report/cityId/101020100
頁面:
在頁面中切換選中城市:
- 停掉
8085
和8086
兩個埠的msa-weather-city-eureka
微服務
重新整理http://localhost:8088/report/cityId/101020100
頁面:
- 停掉
8083
和8084
兩個埠的msa-weather-data-eureka
微服務
重新整理http://localhost:8088/report/cityId/101020100
頁面: