瘋狂Spring Cloud連載(10)——Rest客戶端Feign介紹

本文節選自《瘋狂Spring Cloud微服務架構實戰》html

京東購買地址:https://item.jd.com/12256011.htmljava

噹噹網購買地址:http://product.dangdang.com/25201393.htmlgit

Spring Cloud教學視頻:https://my.oschina.net/JavaLaw/blog/1552993github

Spring Cloud電子書:https://my.oschina.net/JavaLaw/blog/1570383web

本文要點spring

             REST客戶端apache

        Spring Cloud集羣中,各個角色的通訊基於REST服務,所以在調用服務時,就不可避免的須要使用REST服務的請求客戶端。前面的章節中使用了Spring自帶的RestTemplate,RestTemplate使用的是HttpClient發送請求。本章中,將介紹另外一個REST客戶端:Feign。服務器

10 REST客戶端Feign介紹

        在學習Feign前,先了解REST客戶端,本小節將簡單地講述Apache CXF與Restlet這兩款Web Service框架,並使用這兩個框架來編寫REST客戶端,最後再編寫一個Feign的Hello World例子。經過此過程,讓你們能夠對Feign有一個初步的印象。如已經掌握這兩個REST框架,可直接到後面章節學習Feign。架構

        本章的各個客戶端,將會訪問8080端口的「/person/{personId}」和「/hello」這兩個服務中的一個,服務端項目使用「spring-boot-starter-web」進行搭建,本小節對應的服務端項目目錄爲:codes\05\5.1\rest-server。負載均衡

10.1 使用CXF調用REST服務

        CXF是目前一個較爲流行的Web Service框架,是Apache下的一個開源項目。使用CXF能夠發佈和調用各類協議的服務,包括SOAP協議、XML/HTTP等,當前CXF已經對REST風格的Web Service提供支持,能夠發佈或調用REST風格的Web Service。因爲CXF能夠與Spring進行整合使用而且配置簡單,所以獲得許多開發者的青睞,而筆者以往所在公司的大部分項目,均使用CXF來發布和調用Web Service,本章所使用的CXF版本爲3.1.10,Maven中加入如下依賴:

<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-core</artifactId>
			<version>3.1.10</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-rs-client</artifactId>
			<version>3.1.10</version>
		</dependency>

        編寫代碼請求/person/{personId}服務,請見代碼清單5-1。

        代碼清單5-1:codes\05\5.1\rest-client\src\main\java\org\crazyit\cloud\CxfClient.java

package org.crazyit.cloud;

import java.io.InputStream;

import javax.ws.rs.core.Response;

import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.jaxrs.client.WebClient;

/**
 * CXF訪問客戶端
 * @author 楊恩雄
 *
 */
public class CxfClient {

	public static void main(String[] args) throws Exception {
		// 建立WebClient
		WebClient client = WebClient.create("http://localhost:8080/person/1");
		// 獲取響應
		Response response = client.get();
		// 獲取響應內容
		InputStream ent = (InputStream) response.getEntity();
		String content = IOUtils.readStringFromStream(ent);
		// 輸出字符串
		System.out.println(content);
	}
}

        客戶端中,使用了WebClient類發送請求,獲取響應後讀取輸入流,獲取服務返回的JSON字符串。,運行代碼清單5-1,可看到返回的信息。

10.2 使用Restlet調用REST服務

        Restlet是一個輕量級的REST框架,使用它能夠發佈和調用REST風格的Web Service。本小節例子所使用的版本爲2.3.10,Maven依賴以下:

<dependency>
			<groupId>org.restlet.jee</groupId>
			<artifactId>org.restlet</artifactId>
			<version>2.3.10</version>
		</dependency>
		<dependency>
			<groupId>org.restlet.jee</groupId>
			<artifactId>org.restlet.ext.jackson</artifactId>
			<version>2.3.10</version>
		</dependency>

        客戶端實現請見代碼清單5-2。

        代碼清單5-2:codes\05\5.1\rest-client\src\main\java\org\crazyit\cloud\RestletClient.java

package org.crazyit.cloud;

import java.util.HashMap;
import java.util.Map;

import org.restlet.data.MediaType;
import org.restlet.ext.jackson.JacksonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;

/**
 * Restlet客戶端
 * @author 楊恩雄
 *
 */
public class RestletClient {

	public static void main(String[] args) throws Exception {
		ClientResource client = new ClientResource(
				"http://localhost:8080/person/1");
		// 調用get方法,服務器發佈的是GET
		Representation response = client.get(MediaType.APPLICATION_JSON);
		// 建立JacksonRepresentation實例,將響應轉換爲Map
		JacksonRepresentation jr = new JacksonRepresentation(response,
				HashMap.class);
		// 獲取轉換後的Map對象
		Map result = (HashMap) jr.getObject();
		// 輸出結果
		System.out.println(result.get("id") + "-" + result.get("name") + "-"
				+ result.get("age") + "-" + result.get("message"));
	}
}

        代碼清單5-2中使用Restlet的API較爲簡單,在此不過多贅述,但須要注意的是,在Maven中使用Restlet,要額外配置倉庫地址,筆者成書時Apache官方倉庫中,並無Restlet的包。在項目的pom.xml文件中增長如下配置:

<repositories>
		<repository>
			<id>maven-restlet</id>
			<name>Restlet repository</name>
			<url>http://maven.restlet.org</url>
		</repository>
	</repositories>

10.3 Feign框架介紹

        Feign是一個Github上一個開源項目,目的是爲了簡化Web Service客戶端的開發。在使用Feign時,可使用註解來修飾接口,被註解修飾的接口具備訪問Web Service的能力,這些註解中既包括了Feign自帶的註解,也支持使用第三方的註解。除此以外,Feign還支持插件式的編碼器和解碼器,使用者能夠經過該特性,對請求和響應進行不一樣的封裝與解析。

        Spring Cloud將Feign集成到netflix項目中,當與Eureka、Ribbon集成時,Feign就具備負載均衡的功能。Feign自己在使用上的簡便性,加上與Spring Cloud的高度整合,使用該框架在Spring Cloud中調用集羣服務,將會大大下降開發的工做量。

10.4 第一個Feign程序

        先使用Feign編寫一個Hello World的客戶端,訪問服務端的「/hello」服務,獲得返回的字符串。當前Spring Cloud所依賴的Feign版本爲9.5.0,本章案例中的Feign也使用該版本。創建名稱爲「feign-client」的Maven項目,加入如下依賴:

<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>

        新建接口HelloClient,請見代碼清單5-3。

        代碼清單5-3:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\HelloClient.java

package org.crazyit.cloud;

import feign.RequestLine;

/**
 * 客戶端調用的服務接口
 * @author 楊恩雄
 *
 */
public interface HelloClient {

	  @RequestLine("GET /hello")
	  String sayHello();
}

        HelloClient表示一個服務接口,接口的「sayHello」方法中,使用了@RequestLine註解,表示使用GET方法,向「/hello」發送請求。接下來編寫客戶端的運行類,請見代碼清單5-4。

代碼清單5-4:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\HelloMain.java

package org.crazyit.cloud;

import feign.Feign;
import feign.gson.GsonDecoder;

public class HelloMain {

	public static void main(String[] args) {
		// 調用Hello接口
		HelloClient hello = Feign.builder().target(HelloClient.class,
				"http://localhost:8080/");
		System.out.println(hello.getClass().getName());
		System.out.println(hello.sayHello());
	}
}

        運行類中,使用Feign建立HelloClient接口的實例,最後調用接口定義的方法。運行代碼清單5-4,能夠看到返回的「Hello World」字符串,可見接口已經被調用。熟悉AOP的朋友大概已經猜到,Feign實際上會幫咱們動態生成代理類。Feign使用的是JDK的動態代理,生成的代理類,會將請求的信息封裝,交給feign.Client接口發送請求,而該接口的默認實現類,最終會使用java.net.HttpURLConnection來發送HTTP請求。

10.5 請求參數與返回對象

        本案例中有兩個服務,另一個地址爲「/person/{personId}」,須要傳入參數而且返回JSON字符串,編寫第二個Feign客戶端,調用該服務。新建PersonClient服務類,定義調用接口並添加註解,請見代碼清單5-5。

        代碼清單5-5:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\PersonClient.java

package org.crazyit.cloud;

import lombok.Data;
import lombok.NoArgsConstructor;
import feign.Param;
import feign.RequestLine;

/**
 * Person客戶端服務類
 * @author 楊恩雄
 *
 */
public interface PersonClient {

	@RequestLine("GET /person/{personId}")
	Person findById(@Param("personId") Integer personId);
	
	@Data // 爲全部屬性加上setter和getter等方法
	class Person {
		Integer id;
		String name;
		Integer age;
		String message;
	}
}

        定義的接口名稱爲「findById」,參數爲「personId」。須要注意的是,因爲會返回Person實例,咱們在接口中定義了一個Person的類,爲了減小代碼量,使用了Lombok項目,使用了該項目的@Data註解。要使用Lombok,須要添加如下Maven依賴:

<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.18</version>
		</dependency>

        準備好提供服務的客戶端類後,再編寫運行類。運行類基本上與前面的HelloWorld相似,請見代碼清單5-6。

        代碼清單5-6:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\PersonMain.java

package org.crazyit.cloud;

import org.crazyit.cloud.PersonClient.Person;

import feign.Feign;
import feign.gson.GsonDecoder;

/**
 * Person服務的運行主類
 * @author 楊恩雄
 *
 */
public class PersonMain {

	public static void main(String[] args) {
		PersonClient personService = Feign.builder()
				.decoder(new GsonDecoder())
				.target(PersonClient.class, "http://localhost:8080/");
		Person person = personService.findById(2);
		System.out.println(person.id);
		System.out.println(person.name);
		System.out.println(person.age);
		System.out.println(person.message);
	}
}

        調用Person服務的運行類中,添加了解碼器的配置,GsonDecoder會將返回的JSON字符串,轉換爲接口方法返回的對象,關於解碼器等內容,將在後面章節中講述。運行代碼清單5-6,能夠看到最終的輸出。

        本小節使用了CXF、Restlet、Feign來編寫REST客戶端,在編寫客戶端的過程當中,能夠看到Feign的代碼更加「面向對象」,至因而否更加簡潔,則見仁見智。下面的章節,將深刻了解Feign的各項功能。

 

        本文節選自《瘋狂Spring Cloud微服務架構實戰》

        Spring Cloud教學視頻:https://my.oschina.net/JavaLaw/blog/1552993

Spring Cloud電子書:https://my.oschina.net/JavaLaw/blog/1570383

本書代碼共享地址:https://gitee.com/yangenxiong/SpringCloud

相關文章
相關標籤/搜索