天天看點

OpenFeign元件服務間調用時參數傳遞微服務間通信的方式??OpenFeign服務間通信時參數傳遞

OpenFeign元件

  • `微服務間通信的方式??`
    • 1.基于Http應用層協定
    • 2.基于RPC傳輸層協定
  • `OpenFeign服務間通信時參數傳遞`
    • 1.基本資料類型
    • 2.傳遞對象類型
    • 3.傳遞數組和集合類型

微服務間通信的方式??

服務間通信的方式主要有以下兩種:

1.基于Http應用層協定

特點

1.使用http rest方式,使用json作為資料交換的

2.效率較低,但是耦合度低(耦合度低意味着如果不同服務使用不同的技術架構進行開發後,進行通信的成本低)

典型的實作

1.RestTemplate

缺點:

1.服務調用使路徑寫死,耦合度高

2.要想實作負載均衡,必須得結合Ribbon元件,造成備援代碼

2.OpenFeign(推薦)

特點:

1.OpenFeign元件是spring團隊基于netflix的Feign元件進行封裝和擴充形成的自己的一個項目,它是一個僞HttpClient;

OpenFeign是一個僞HTTP用戶端,底層還是RestTemplate,是對RestTemplate的封裝

2.OpenFeign支援可插拔的編碼器和解碼器。

比如幫我們預設實作json和其他資料類型的裝換

3.OpenFeign預設內建了Ribbon

預設實作了負載均衡的效果,不需要我們再像RestTemlate那樣,利用ribbon編寫實作負載均衡的相關代碼;

并且springcloud為feign添加了

springmvc注解

的支援。

4.使用友善,代碼量少

使用時隻需要添加幾個注解,編寫一個接口類即可,耦合度低

2.基于RPC傳輸層協定

特點

1.使用的是傳輸層的協定,以二進制方式傳遞資料

2.效率高,但是耦合度高,如果不同服務使用不同的技術架構進行開發後,進行通信的成本高

典型的RPC架構:Dubbo

總結:`在springcloud中服務間調用方式主要是使用 http restful方式進行服務間調用

OpenFeign服務間通信時參數傳遞

1.基本資料類型

GoodsClient接口

@FeignClient(value = "GOODS")
public interface GoodsClient {

    /*
    * 注意:這裡的方法需要保證傳回類型,形參,請求路徑一緻
    * 方法名可以與被調用的服務名不同
    *
    * feign預設給我們實作了負載均衡!!
    * */
    @GetMapping("/test")
    String test(String name,Integer age);
}
           

商品服務controller

@GetMapping("/test")
    public String test(String name,Integer age){
        log.info("name:{},age:{}",name,age);
        return name + age;
    }
           

CategoryController調用商品服務的test方法

@GetMapping
    public String testService(){
        String test = goodsClient.test("jw", 20);
        return test;
    }
           

啟動報錯顯示太多參數

Caused by: java.lang.IllegalStateException: Method has too many Body parameters: public abstract java.lang.String com.jw.feignclient.GoodsClient.test(java.lang.String,java.lang.Integer)

原因是:

我們知道通過QueryString傳遞有兩種方式,一種是

/test?name=jw&age=20的形式

另一種是rest的方式,直接把參數寫在路徑中

/test/jw/20

由于OpenFeign是僞用戶端,底層在調用服務時還是基于RestTemplate,當我們通過GoodsClient調用test服務是,GoodsClient會把接收的參數傳遞給RestTemplate進行封裝;此時RestTemplate不知道該基于哪種方式進行封裝,是以會報錯;

如果我們隻寫一個參數,那麼預設就是?name=xx的形式

如果有多個參數就需要我們用注解顯示聲明

@RequestParams

如果是想以

/test?name=xxx&age=xxx

的形式傳遞參數,那麼使@RequestParams;

@FeignClient(value = "GOODS")
public interface GoodsClient {

    /*
    * 注意:這裡的方法需要保證傳回類型,形參,請求路徑一緻
    * 方法名可以與被調用的服務名不同
    *
    * feign預設給我們實作了負載均衡!!
    * */
   
    @GetMapping("/test")
    String test(@RequestParam String name,@RequestParam Integer age);
}
           

注意:如果我們@RequestParam指派,被調用方需要一緻

@GetMapping("/test")
String test(@RequestParam("aa") String name,@RequestParam("bb") Integer age);

//商品服務
@GetMapping("/test")
public String test(String aa,Integer bb){
     	log.info("name:{},age:{}",aa,bb);
       return aa + bb;
}

@GetMapping("/test")
public String test(@RequestParam("aa") String name,@RequestParam("bb") Integer age){
     	log.info("name:{},age:{}",name,age);
       return name + age;
}
           

@PathVariable

如果是想以

/test/jw/20

形式傳遞參數,那麼使用@PathVariable

@FeignClient(value = "GOODS")
public interface GoodsClient {

    /*
    * 注意:這裡的方法需要保證傳回類型,形參,請求路徑一緻
    * 方法名可以與被調用的服務名不同
    *
    * feign預設給我們實作了負載均衡!!
    * */

    @GetMapping("/test1/{name}/{age}")
    String test1(@PathVariable("name") String name, @PathVariable("age") Integer age);
}

	//商品服務controller
	@GetMapping("/test1/{name}/{age}")
    public String test1(@PathVariable("name")String name,@PathVariable("age") Integer age){
        log.info("name:{},age:{}",name,age);
        return name+age;
    }
    
  	//**CategoryController調用商品服務的test1方法**
	 @GetMapping
    public String testService(){
        String test = goodsClient.test1("jw", 20);
        return test;
    }
           

2.傳遞對象類型

使用

@RequestBody

注解會把對象以aplication/json的形式傳參,被調用的服務也需要加上@RequestBody該注解,把收到的json轉成對應的對象

//categoryController
	@GetMapping
    public String testService(){
        //String test = goodsClient.test1("jw", 20);
        goodsClient.save(new Goods(1,"aa",22.12,new Date()));
        return null;
    }

    //接口
	@FeignClient(value = "GOODS")
	public interface GoodsClient {
    /*
    * 注意:這裡的方法需要保證傳回類型,形參,請求路徑一緻
    * 方法名可以與被調用的服務名不同
    *
    * feign預設給我們實作了負載均衡!!
    * */
    @PostMapping("/savegoods")
    void save(@RequestBody Goods goods);
	}
	
 	//GoodsController
	@PostMapping("/savegoods")
    public void save(@RequestBody Goods goods){
        log.info("goods:{}",goods);
    }
           

3.傳遞數組和集合類型

**數組類型使用@RequestParam會把ids數組拼裝成

/test3/?ids=1&ids=2&ids=3

的形式

@FeignClient(value = "GOODS")
	public interface GoodsClient {
    @GetMapping("/test3")
    void test3(@RequestParam("ids") String[] ids);
	}
	==================================
	  //goodsController
	@GetMapping("/test3")
    public void test3( String[] ids){
        log.info("ids:{}",ids);
    }	
           

集合類型

springMVC中get方式是不能用集合作參數的

比如以

/test4/?ids=1&ids=2&ids=3

,接收不到

//不行
   @GetMapping("/test4")
   public void test4(ArrayList<String> ids){
       
   }
 
           

如果硬要接收集合,那麼需要把集合作為類的屬性

@GetMapping("/test3")
    public void test3( GoodsVO vo){
        log.info("ids:{}",ids);
    }	
	
	class ProductVO{
    private ArrayList<String> ids;

    public ArrayList<String> getIds() {
        return ids;
    }

    public void setIds(ArrayList<String> ids) {
        this.ids = ids;
    }
}
           

此時在FeignClient中還是同數組一樣,因為@RequestParam會把接收到的ids拼接成/test4/?ids=1&ids=2&ids=3,在GoodController接收時,就會去Goodvo中找到ids進行指派

@FeignClient(value = "GOODS")
   public interface GoodsClient {
   @GetMapping("/test4")
   void test3(@RequestParam("ids") String[] ids);
   }
           

注意:這裡是GET方式需要接收一個List集合

如果是POST方式直接加上@RequestBody注解以json方式傳遞即可