天天看點

JAX-RS 2.0 REST 用戶端

JAX-RS 2.0對用戶端API進行了标準化。用戶端API通過HTTP請求Web資源,同樣符合統一接口和REST架構風格。與Apache HTTP Client和HttpURLConnection相比,用戶端API具備對REST感覺的高層API,可以和Providers內建,傳回值直接對應高層的業務類執行個體。

1. 用戶端接口

REST用戶端主要包括三個接口:javax.ws.rs.client.Client、javax.ws.rs.client.WebTarget和javax.ws.rs.client.Invocation。

1.1 Client接口

Client内部要管理用戶端通信底層實作所需的各種對象,它是一個重量級的對象,應該盡量少地構造Client執行個體。此外接口要求其執行個體要有關閉連接配接的保障,否則會造成記憶體洩露。

Jersey對Client接口的實作類是JerseyClient。通常使用構造模式,使用ClientBuilder建立執行個體。示例如下:

ClientConfig clientConfig = new ClientConfig();
//注冊Provider
clientConfig.register(MyProvider.class);
//注冊Feature
clientConfig.register(MyFeature.class);
//注冊Filter
clientConfig.register(new AnotherClientFilter());
//建立Client
Client client = ClientBuilder.newClient(clientConfig);
//通過property設定相關屬性
client.property("MyProperty", "MyValue");

//配置完畢後,可以通過getConfiguration()擷取配置資訊
Configuration configuration = client.getConfiguration();
Map<String, Object> properties = configuration.getProperties();
Iterator<Entry<String, Object>> it = properties.entrySet().iterator();
...                

Client接口還提供了對用戶端的安全連接配接和異步支援。

1.2 WebTarget接口

WebTarget接口為REST用戶端實作資源定位,可以定義請求資源的位址、查詢參數和媒體類型等資訊。Jersey中的WebTarget接口實作類是JerseyWebTarget。

WebTarget對象接收配置參數的方法是通過方法鍊,采用不變模式完成。如果分開寫每次都傳回一個新的WebTarget對象,如果不将其覆值會造成資訊丢失。

WebTarget webTarget = client.target(BASE_URI);
webTarget.path("books").path("book").queryParam("bookId", "1");                

1.3 Invocation接口

當WebTarget接口完成資源定位後,Invocation接口向REST服務端發起請求。請求包括同步和異步方式,由Invocation接口内部的Builder接口定義。Jersey中的Invocation接口實作類是JerseyInvocation。

final Invocation.Builder invocationBuilder = webTarget.request();

//以多種方式請求資料
final Book book = invocationBuilder.get(Book.class);
Response response = invocationBuilder.post(userEntity);
invocationBuilder.put(userEntity);                

JAX-RS 2.0的REST架構無需開發者編碼實作對用戶端執行個體的資源管理,Response執行個體的readEntity()在傳回響應實體的同時,就完成了對用戶端資源的釋放。

2. Connector

Connector接口是REST用戶端底層連接配接器接口,Jersey提供了4個實作:

  • HttpUrlConnector REST用戶端的預設連接配接器
  • ApacheConnector
  • GrizzlyConnector
  • InMemoryConnector 不是真實的HTTP連接配接器,而是使用JVM調用來模拟HTTP請求通路。

2.1 預設連接配接器

預設情況下,Jersey的Client初始化時會構造一個HttpUrlConnector執行個體作為連接配接器。

2.2 Apache連接配接器

ApacheConnector是基于Apache HTTP Client的連接配接器實作,比預設連接配接器功能更完整。可以實作代理伺服器設定、逾時設定。示例如下:

final ClientConfig clientConfig = new ClientConfig();

//代理伺服器配置
clientConfig.property(ApacheClientProperties.PROXY_URI, "http://192.168.0.100");
clientConfig.property(ApacheClientProperties.PROXY_USERNAME, "user");
clientConfig.property(ApacheClientProperties.PROXY_PASSWORD , "pwd");
//連接配接逾時配置
clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 1000);
//讀取逾時配置,指連接配接和資源定位成功後,用戶端接收服務響應的最長時間
clientConfig.property(ClientProperties.READ_TIMEOUT, 2000);

clientConfig.connectorProvider(new ApacheConnectorProvider());
client = ClientBuilder.newClient(clientConfig);                

2.3 Grizzly連接配接器

GrizzlyConnector是Grizzly提供的連接配接器實作,内部使用異步處理用戶端com.ning.http.client.AsyncHttpClient類作為底層的連接配接。

final ClientConfig clientConfig = new ClientConfig();
clientConfig.property("TestKey", "TestValue");

clientConfig.connectorProvider(new GrizzlyConnectorProvider());
Client client = ClientBuilder.newClient(clientConfig);                

2.4 HTTP連接配接池

既然Client是一個重型元件,是以頻繁地建立Client執行個體會影響總體性能。一種常見的解決方案是使用HTTP連接配接池來管理連接配接。下例使用ApacheConnector來實作HTTP連接配接池:

final ClientConfig clientConfig = new ClientConfig();
final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
//設定最大連接配接數
cm.setMaxTotal(20000);
//設定每條路由的預設最大連接配接數
cm.setDefaultMaxPerRoute(10000);
clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, cm);

clientConfig.connectorProvider(new ApacheConnectorProvider());
client = ClientBuilder.newClient(clientConfig);                

後記

通常REST式的Web服務會按子產品分别提供獨立的Web服務,而子產品之間的調用通過Web服務的REST API來實作。也就是說每個子產品對其他子產品的調用就是用戶端請求。為了避免每次請求時重複編寫構造用戶端執行個體的代碼,可以封裝Client到公共子產品,減少代碼備援。

參考:《Java RESTful Web Service實戰》

轉載自:http://blog.ubone.com/blog/2015/04/12/rest-ke-hu-duan/