第一個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);
下面貼上運行結果