什么是Feign,Feign如何使用,Feign與CXF的區別(包括如何使用Feign自定義客戶端)


第一個Feign程序

 

編碼器:如果服務端只接受JSON字符串格式/XML,那么我們客戶端使用的是對象。在這種情況下,我們可以使用編碼器將對象轉換成JSON字符串/XML。
解碼器:將服務端的響應結果對象,轉換為客戶端的對象。這個時候就需要用到解碼器。

 

1. Feign被集成到SpringCloud Netflix模塊,當Eureka,Ribbon集成的時候呢,Feign就具備了負載均衡的功能。Feign本身使用就很簡便,再加上與SpringCloud的整合,將很大程度上降低我們開發的工作量。

2. 它是Github上面的一個開源項目,目的是為了簡化WebService客戶端的開發,在使用Feign的時候 可以使用注解來修飾接口,被修飾的接口就具有了訪問webservice的能力,這些注解呢 可以使用Feign的自帶注解,也可以支持使用第三方的注解。Feign還支持插件式的編碼器和解碼器,使用者可以通過這些特性,對請求和響應進行封裝和解析。

Feign會更加的面向對象,下面我們使用Feign來對比一下CXF。在這之前我們需要准備對外提供接口。

如果沒有接口等項目的朋友,可以參照前幾章的“SpringCloud 中使用 Ribbon(默認輪詢規則 + 自定義規則)”搭建(只搭建服務器與服務提供者即可)

 

這里我們一次把依賴CXF、Feign的依賴全部引入:pom.xml

<dependencies>
    <!-- CXF 依賴 -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-core</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-client</artifactId>
        <version>3.1.0</version>
    </dependency>

    <!-- Feign 依賴 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-core</artifactId>
        <version>9.5.0</version>
    </dependency>
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-gson</artifactId>
        <version>9.5.0</version>
    </dependency>
    <!-- 如果請求格式用XML的時候,需要加入以下XML依賴 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-jaxb</artifactId>
        <version>9.5.0</version>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.2.8</version>
    </dependency>
</dependencies>

 

 下面我們編寫一個CXF客戶端,進行測試:CxfClient.java

public class CxfClient {
    
    public static void main(String[] args) throws IOException {
        // 創建 WebClient
        WebClient client = WebClient.create("http://localhost:9090/getPoliceById/123");
        // 獲取響應
        Response response = client.get();
        // 獲取響應內容
        InputStream is = (InputStream) response.getEntity();
        String content = IOUtils.readStringFromStream(is);
        // 打印結果
        System.out.println("請求結果:" + content);
    }

}

亂碼的問題不用管,我們就看 WebClient.create 方法中的url,url多的話,維護起來也麻煩,而且還需要對流進行操作。。。接下來,我們編寫一個Feign程序,與CXF進行一下對比

 

 在文章的一開始,提到了 Feign 程序會更加的面向對象,所以我們先創建一個實體類,用來接收結果對象:Police.java

public class Police {
    
    private String id;// 警察編號,用來保存用戶輸入的參數
    private String url;// 處理請求的服務器url
    private String message;// 提示信息
    
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    
}

 

 其次,我們創建一個接口類:FeignService.java

public interface FeignService {
    
    @RequestLine("GET /getPolice")
    public String getPolice();
    
    @RequestLine("GET /getPolice")
    public Police getPoliceObj();
    
    @RequestLine("GET /getPoliceById/{id}")
    public String getPoliceById(@Param("id") String id);
    
    /**
     * 發送JSON對象,返回字符串
     * @param police
     * @return
     */
    @RequestLine("POST /createPolice")
    @Headers("Content-Type: application/json")// 這里要指定請求類型
    public String createPolice(Police police);
    
    /**
     * 發送XML對象,返回字符串
     * @return
     */
    @RequestLine("POST /createXmlPolice")
    @Headers("Content-Type: application/xml")// 這里要指定請求類型
    public Police createXmlPolice(Police police);

}

 

 最后,我們再創建一個測試類,查看結果:TestMain.java

public static void main(String[] args) {
    /**
     * 根據ID獲取派出警察,返回JSON字符串
     */
    FeignService client_1 = Feign.builder().target(FeignService.class, "http://localhost:9090");
    String policeStr = client_1.getPolice();
    System.out.println("返回JSON字符串:"+policeStr);
    String policeByIdStr = client_1.getPoliceById("123");
    System.out.println("根據ID獲取派出警察,返回JSON字符串:"+policeByIdStr);
    
    /**
     * 返回警察對象
     */
    FeignService client_2 = Feign.builder().decoder(new GsonDecoder()).target(FeignService.class, "http://localhost:9090");
    Police police = client_2.getPoliceObj();
    System.out.println("返回警察對象:");
    System.out.println("  url:"+police.getUrl());
    System.out.println("  message:"+police.getMessage());
    
    /**
     * 發送JSON對象,返回字符串
     */
    FeignService client_3 = Feign.builder().encoder(new GsonEncoder()).target(FeignService.class, "http://localhost:9090");
    Police police_json = new Police();
    police_json.setMessage("你好");
    String createResult = client_3.createPolice(police_json);
    System.out.println("發送JSON格式參數,返回字符串:"+createResult);
    
    /**
     * 發送XML對象,返回字符串
     * 使用XML進行發送與接收時,實體類需要使用注解:
     * 類上注解:@XmlRootElement
     * 字段注解:@XmlElement
     * get方法使用注解:@XmlTransient */
    JAXBContextFactory encoder = new JAXBContextFactory.Builder().build();
    FeignService client_4 = Feign.builder()
            .encoder(new JAXBEncoder(encoder))
            .decoder(new JAXBDecoder(encoder))
            .target(FeignService.class, "http://localhost:9090");
    Police police_xml = new Police();
    police_xml.setMessage("你好");
    Police policeResult = client_4.createXmlPolice(police_xml);
    System.out.println("發送XML格式參數,返回字符串:"+policeResult.getMessage());
}

但是如果向接口傳入xml格式值,那接口應該怎么定義呢?

// 接收xml,返回xml
@RequestMapping(value="/createXmlPolice", method=RequestMethod.POST, produces=MediaType.APPLICATION_XML_VALUE, consumes=MediaType.APPLICATION_XML_VALUE)
public String createXmlPolice(@RequestBody Police police){
    return "<police><message>"+police.getMessage()+"</message></police>";
}

OK,這樣子就可以傳遞xml格式的參數了。。。那么下面貼一下以上main方法中的所有執行結果

 

 

額外再說一下,Feign的客服端 也是可插拔的,,下面教大家如何實現自定義客戶端,並訪問

首先需要自定義一個客戶端,需要實現Feign的Client接口:MyClient.java

public class MyClient implements Client {

    @Override
    public Response execute(Request request, Options options) throws IOException {
        try {
            // 創建一個默認的客戶端
            CloseableHttpClient httpClient = HttpClients.createDefault();
            // 獲取調用的HTTP方法
            final String method = request.method();
            // 創建一個HttpClient的Request
            HttpRequestBase httpRequest = new HttpRequestBase() {
                @Override
                public String getMethod() {
                    return method;
                }
            };
            // 設置請求地址
            httpRequest.setURI(new URI(request.url()));
            // 執行請求,獲取響應
            HttpResponse httpResponse = httpClient.execute(httpRequest);
            // 獲取響應的主體內容
            byte[] body = EntityUtils.toByteArray(httpResponse.getEntity());
            // 將HttpClient的響應對象轉換為Feign的Response
            Response feignResponse = Response.builder()
                    .body(body)
                    .headers(new HashMap<String, Collection<String>>())
                    .status(httpResponse.getStatusLine().getStatusCode())
                    .build();
            return feignResponse;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

編寫一個測試main方法:

/**
 * 使用可插拔式的自定義client客戶端,進行請求訪問
 */
FeignService client_5 = Feign.builder().client(new MyClient()).target(FeignService.class, "http://localhost:9090");
String policeStr = client_5.getPolice();
System.out.println("返回JSON字符串:"+policeStr);

下面貼上運行結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM