API網關 | 從0開始構建SpringCloud微服務(12)

照例附上項目github連接java

本項目實現的是將一個簡單的天氣預報系統一步一步改形成一個SpringCloud微服務系統的過程。本章主要講解API網關git



項目存在的問題

在目前的項目中咱們構建了許多的API微服務,當第三方服務想要調用咱們的API微服務的時候是經過微服務的名稱進行調用的,沒有一個統一的入口。github



使用API網關的意義

  • 集合多個API
  • 統一API入口

API網關就是爲了統一服務的入口,能夠方便地實現對平臺的衆多服務接口進行管控,對訪問服務的身份進行驗證,防止數據的篡改等。web

咱們的一個微服務可能須要依賴多個API微服務,API網關能夠在中間作一個api的彙集。spring

那麼咱們的微服務只須要統一地通過API網關就能夠了(只須要依賴於API網關就能夠了),不用關心各類API微服務的細節,須要調用的API微服務由API網關來進行轉發。後端



使用API網關的利與弊

API網關的利

  • 避免將內部信息泄露給外部
  • 爲微服務添加額外的安全層
  • 支持混合通訊協議
  • 下降構建微服務的複雜性
  • 微服務模擬與虛擬化


API網關的弊

  • 在架構上須要額外考慮更多編排與管理
  • 路由邏輯配置要進行統一的管理
  • 可能引起單點故障



API網關的實現

Zuul:SpringCloud提供的API網關的組件

Zuul是Netflix開源的微服務網關,他能夠和Eureka,Ribbon,Hystrix等組件配合使用。Zuul組件的核心是一系列的過濾器,這些過濾器能夠完成如下功能:api

  1. 身份認證和安全: 識別每個資源的驗證要求,並拒絕那些不符的請求
  2. 審查與監控:
  3. 動態路由:動態將請求路由到不一樣後端集羣
  4. 壓力測試:逐漸增長指向集羣的流量,以瞭解性能
  5. 負載分配:爲每一種負載類型分配對應容量,並棄用超出限定值的請求
  6. 靜態響應處理:邊緣位置進行響應,避免轉發到內部集羣
  7. 多區域彈性:跨域AWS Region進行請求路由,旨在實現ELB(ElasticLoad Balancing)使用多樣化

Spring Cloud對Zuul進行了整合和加強。目前,Zuul使用的默認是Apache的HTTP Client,也可使用Rest Client,能夠設置ribbon.restclient.enabled=true。跨域



集成Zuul

在原來項目的基礎上,建立一個msa-weather-eureka-client-zuul做爲API網關。安全

添加依賴

<dependency>
     <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>


添加註解

添加@EnableZuulProxy啓用Zuul的代理功能。架構

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


添加配置

這裏配置的是設置路由的url。

當有人訪問 /city/ 路徑的時候,就對訪問這個路徑的請求作一個轉發,轉發到msa-weather-city-eureka服務中去,同理,當有人訪問 /data/ 路徑的時候,API網關也會將這個請求轉發到msa-weather-data-eureka服務中去。

zuul:
  routes:
    city: 
      path: /city/**
      service-id: msa-weather-city-eureka
    data: 
      path: /data/**
      service-id: msa-weather-data-eureka



微服務依賴API網關

原來天氣預報微服務依賴了城市數據API微服務,以及天氣數據API微服務,這裏咱們對其進行修改讓其依賴API網關,讓API網關處理天氣預報微服務其餘兩個微服務的調用。

首先刪去原來調用其餘兩個API微服務的Feign客戶端——CityClient以及WeatherDataClient,建立一個新的Feign客戶端——DataClient。

package com.demo.service;

import java.util.List;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.demo.vo.City;
import com.demo.vo.WeatherResponse;

@FeignClient("msa-weather-eureka-client-zuul")
public interface DataClient {

    //獲取城市列表
    @RequestMapping(value="/city/cities",method=RequestMethod.GET)
    List<City> listCity()throws Exception;
    
    //經過城市Id查詢對應城市的天氣數據
    @RequestMapping(value="/data/weather/cityId",method=RequestMethod.GET)
    WeatherResponse getDataByCityId(@RequestParam("cityId")String cityId);
}

在service中使用該客戶端對API網關進行調用,API網關根據咱們請求的路徑去調用相應的微服務。

@Service
public class WeatherReportServiceImpl implements WeatherReportService{
    //@Autowired 
    //private WeatherDataClient weatherDataClient;
    
    @Autowired
    private DataClient dataClient;
    
    //根據城市Id獲取天氣預報的數據
    @Override
    public Weather getDataByCityId(String cityId) {
        //由天氣數據API微服務來提供根據城市Id查詢對應城市的天氣的功能
        WeatherResponse resp=dataClient.getDataByCityId(cityId);
        Weather data=resp.getData();
        return data;
    }
}

在controller也是同理。

//傳入城市Id獲得對應城市的天氣數據
    @GetMapping("/cityId/{cityId}")
    public Weather getReportByCityId(@PathVariable("cityId")String cityId,Model model)throws Exception{
        //獲取城市Id列表
        //由城市數據API微服務來提供數據
        List<City>cityList=null;
        
        try {
            cityList=dataClient.listCity();
        }catch (Exception e) {
            logger.error("Exception!",e);
        }
        
        Weather weather=weatherReportService.getDataByCityId(cityId);
        
        return weather;
    }



測試結果

圖片描述


圖片描述

相關文章
相關標籤/搜索