日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

1、Feign簡介

Feign是一種聲明式、模板化的HTTP客戶端。使用Feign,可以做到聲明式調用。

盡管Feign目前已經不再迭代,處于維護狀態,但是Feign仍然是目前使用最廣泛的遠程調用框架之一。

在SpringCloud Alibaba的生態體系內,有另一個應用廣泛的遠程服務調用框架Dubbo,在后面我們會接觸到。

Feign是在RestTemplate 和 Ribbon的基礎上進一步封裝,使用RestTemplate實現Http調用,使用Ribbon實現負載均衡。

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

接下來,我們開始學習Feign的使用,非常簡單!

2、Feign使用

2.1、引入OpenFeign

在前面的章節里,我們已經引入了SpringCloud,現在我們只需要在需要引入的子模塊中添加依賴:

復制代碼

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

2.2、Feign遠程調用

我們現在來完成一個業務:添加商品

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

這個業務涉及兩個子服務,添加商品的時候同時要添加庫存,查詢商品的時候,同時要查詢庫存。商品服務作為消費者,庫存服務作為生產者。

2.2.1、服務提供者

作為服務提供者的庫存服務很簡單,提供兩個接口添加庫存、根據商品ID獲取庫存量。

  • 控制層

復制代碼

@RestController
@RequestMApping("/shop-stock/api")
@Slf4j
@Api(value = "商品服務對外接口", tags = "商品服務對外接口")
public class ShopStockApiController {
    @Autowired
    private IShopStockService shopStockService;

    @PostMapping(value = "/add")
    @ApiOperation("添加庫存")
    public Integer addStock(@RequestBody StockAddDTO stockAddDTO) {
        log.info("client call add stock interface,param:{}", stockAddDTO);
        return this.shopStockService.addStockApi(stockAddDTO);
    }

    @GetMapping(value = "/account/get")
    @ApiOperation("根據商品ID獲取庫存量")
    public Integer getAccountById(@RequestParam Integer goodsId) {
        return this.shopStockService.getAccountById(goodsId);
    }
}

注意看,為了演示出本地調用類似的效果,這兩個接口和普通的前后端接口不同。

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

我們沒有返回之前定下的統一返回結果CommonResult,而是直接返回了數據。

  • 業務層普通的增、查而已

復制代碼

    /**
     * 添加庫存-直接返回主鍵
     *
     * @param stockAddDTO
     * @return
     */
    public Integer addStockApi(StockAddDTO stockAddDTO) {
        ShopStock stock = new ShopStock();
        stock.setGoodsId(stockAddDTO.getGoodsId());
        stock.setInventory(stockAddDTO.getAccount());
        log.info("準備添加庫存,參數:{}", stock.toString());
        this.baseMapper.insert(stock);
        Integer stockId =stock.getStockId();
        log.info("添加庫存成功,stockId:{}", stockId);
        return stockId;
    }

    /**
     * 根據商品ID獲取商品庫存
     *
     * @param goodsId
     * @return
     */
    public Integer getAccountById(Integer goodsId) {
        ShopStock stock = this.getOne(Wrappers.<ShopStock>lambdaQuery().eq(ShopStock::getGoodsId, goodsId));
        Integer account = stock.getInventory();
        return account;
    }

  • 添加庫存實體類

復制代碼

@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "庫存添加", description = "")
public class StockAddDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "商品主鍵")
    private Integer goodsId;

    @ApiModelProperty(value = "數量")
    private Integer account;
}

至此,我們的服務提供者的相關開發到此完成,打開地址
http://localhost:8050/doc.html ,可以看到我們開發的接口:

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

2.2.2、服務消費者

好了,接下里要開始我們的服務消費者,也就是商品服務的開發。

  • 遠程調用Feign客戶端

聲明式調用——看一下Feign客戶端的代碼,你就知道什么是聲明式調用:

復制代碼

/**
 * @Author: 三分惡
 * @Date: 2021/5/26
 * @Description: 庫存服務feign客戶端
 **/
@FeignClient(value = "stock-service")
public interface StockClientFeign {

    /**
     * 調用添加庫存接口
     *
     * @param stockAddDTO
     * @return
     */
    @PostMapping(value = "/shop-stock/api/add")
    Integer addStock(@RequestBody StockAddDTO stockAddDTO);

    /**
     * 調用根據商品ID獲取庫存量接口
     *
     * @param goodsId
     * @return
     */
    @GetMapping(value = "/shop-stock/api/account/get")
    Integer getAccountById(@RequestParam(value = "goodsId") Integer goodsId);
}
  • 定義完成之后,我們還要在啟動類上加上注解@EnableFeignClients去掃描Feign客戶端。

復制代碼

@SpringBootApplication
@MapperScan("cn.fighter3.mapper")
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "cn.fighter3.client")
public class EshopGoodsApplication {

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

使用Feign客戶端也很簡單,直接在需要使用的地方注入就行了。

復制代碼

@Autowired
private StockClientFeign stockClientFeign;
  • 商品服務控制層

復制代碼

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 三分惡
 * @since 2021-05-18
 */
@RestController
@RequestMapping("/shop-goods")
@Api(value = "商品管理接口", tags = "商品接口")
@Slf4j
public class ShopGoodsController {

    @Autowired
    private IShopGoodsService goodsService;

    @PostMapping(value = "/add")
    @ApiOperation(value = "添加商品")
    public CommonResult addGoods(@RequestBody GoodsAddDTO goodsAddDTO) {
        return this.goodsService.addGoods(goodsAddDTO);
    }

    @GetMapping(value = "/get/by-id")
    @ApiOperation(value = "根據ID獲取商品")
    public CommonResult<GoodsVO> getGoodsById(@RequestParam Integer goodsId) {
        return this.goodsService.getGoodsById(goodsId);
    }

}
  • 服務層

在服務層除了對商品庫的操作之外,還通過Feign客戶端遠程調用庫存服務的接口。

復制代碼

@Service
@Slf4j
public class ShopGoodsServiceImpl extends ServiceImpl<ShopGoodsMapper, ShopGoods> implements IShopGoodsService {

    @Autowired
    private StockClientFeign stockClientFeign;

    /**
     * 添加商品
     *
     * @param goodsAddDTO
     * @return
     */
    public CommonResult addGoods(GoodsAddDTO goodsAddDTO) {
        ShopGoods shopGoods = new ShopGoods();
        BeanUtils.copyProperties(goodsAddDTO, shopGoods);
        this.baseMapper.insert(shopGoods);
        log.info("添加商品,商品主鍵:{}", shopGoods.getGoodsId());
        log.info(shopGoods.toString());
        StockAddDTO stockAddDTO = StockAddDTO.builder().goodsId(shopGoods.getGoodsId()).account(goodsAddDTO.getAccount()).build();
        log.info("準備添加庫存,參數:{}", stockAddDTO.toString());
        Integer stockId = this.stockClientFeign.addStock(stockAddDTO);
        log.info("添加庫存結束,庫存主鍵:{}", stockId);
        return CommonResult.ok();
    }

    /**
     * 獲取商品
     *
     * @param goodsId
     * @return
     */
    public CommonResult<GoodsVO> getGoodsById(Integer goodsId) {
        GoodsVO goodsVO = new GoodsVO();
        //獲取商品基本信息
        ShopGoods shopGoods = this.baseMapper.selectById(goodsId);
        BeanUtils.copyProperties(shopGoods, goodsVO);
        //獲取商品庫存數量
        Integer account = this.stockClientFeign.getAccountById(goodsId);
        log.info("商品數量:{}", account);
        goodsVO.setAccount(account);
        return CommonResult.ok(goodsVO);
    }
}
  • 實體類添加庫存實體類和庫存服務相同,略過,商品展示實體類

復制代碼

@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "商品", description = "")
public class GoodsVO implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "商品主鍵")
    private Integer goodsId;

    @ApiModelProperty(value = "商品名稱")
    private String goodsName;

    @ApiModelProperty(value = "價格")
    private BigDecimal price;

    @ApiModelProperty(value = "商品介紹")
    private String description;

    @ApiModelProperty(value = "數量")
    private Integer account;
}

2.2.3、效果演示

接下來啟動nacos-server,商品服務,庫存服務。

訪問地址
http://127.0.0.1:8848/nacos/index.html ,登錄之后,可以在服務列表里看到我們注冊的兩個服務:

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

訪問商品服務Knife4j地址:
http://localhost:8020/doc.html ,可以看到添加商品和根據商品ID查找商品的接口,分別調試調用:

  • 添加商品
SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

  • 根據ID獲取商品
SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

可以看到各自對應的數據庫也有數據生成:

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

整體的遠程調用示意圖大概如下:

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

2.3、Ribbon負載均衡

關于負載均衡,這里偷個懶,就不再演示了。

感興趣的可以把庫存服務打包,以不同的端口啟動,然后添加商品,通過日志查看商品服務調用的負載情況。

Feign負載均衡是通過Ribbon實現,Ribbon是一種客戶端的負載均衡——也就是從注冊中心獲取服務列表,由客戶端自己決定調用哪一個遠程服務。

SpringCloud Alibaba實戰(使用OpenFeign服務調用)

 

Ribbon的主要負載均衡策略有以下幾種:

規則名稱

特點

AvailabilityFilteringRule

過濾掉一直連接失敗的被標記為circuit tripped的后端Server,并 過濾掉那些高并發的后端Server或者使用一個AvailabilityPredicate 來包含過濾server的邏輯,其實就是檢查status里記錄的各個server 的運行狀態

BestAvailableRule

選擇一個最小的并發請求的server,逐個考察server, 如果Server被tripped了,則跳過

RandomRule

隨機選擇一個Server

ResponseTimeWeightedRule

已廢棄,作用同WeightedResponseTimeRule

WeightedResponseTimeRule

根據響應時間加權,響應時間越長,權重越小,被選中的可能性越低

RetryRule

對選定的負載均衡策略加上重試機制,在一個配置時間段內當 選擇Server不成功,則一直嘗試使用subRule的方式選擇一個 可用的Server

RoundRobinRule

輪詢選擇,輪詢index,選擇index對應位置的Server

ZoneAvoidanceRule

默認的負載均衡策略,即復合判斷Server所在區域的性能和Server的可用性 選擇Server,在沒有區域的環境下,類似于輪詢(RandomRule)

這里就不再展開講了,感興趣的自行了解。

3、意外狀況

  • 發現遠程調用的時候出現讀取響應結果超時的情況:
JAVA.net.SocketTimeoutException: Read timed out

修改Ribbon超時配置就行了:

# ribbon超時時間
ribbon:
  ReadTimeout: 30000
  ConnectTimeout: 30000
  • Feign接口中,使用@RequestParam報錯

發現報錯:

Caused by: java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0

Feign聲明里需要加上value:

Integer getAccountById(@RequestParam(value = "goodsId") Integer goodsId);

分享到:
標簽:SpringCloud
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定