Jersey Client 的API

您所在的位置:网站首页 参数配置client Jersey Client 的API

Jersey Client 的API

2023-04-19 02:34| 来源: 网络整理| 查看: 265

JAX-RS Client API是 流式 Java based 的Restful API.

这个client 有三个目的:

封装复杂度,提供统一规范的接口;

使客户端和server尽量解耦,彼此的开发简单

提供统一的通路和客制化接口。

这三个标准是所有client 都希望达到的目的,从目前来看Jersey的Client 是实现的最好的之一。JerseyClient API 请看下面的sample,

标准API ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MyClientResponseFilter.class); clientConfig.register(new AnotherClientFilter()); Client client = ClientBuilder.newClient(clientConfig); client.register(ThirdClientFilter.class); WebTarget webTarget = client.target("http://example.com/rest"); webTarget.register(FilterForExampleCom.class); WebTarget resourceWebTarget = webTarget.path("resource"); WebTarget helloworldWebTarget = resourceWebTarget.path("helloworld"); WebTarget helloworldWebTargetWithQueryParam = helloworldWebTarget.queryParam("greeting", "Hi World!"); Invocation.Builder invocationBuilder = helloworldWebTargetWithQueryParam.request(MediaType.TEXT_PLAIN_TYPE); invocationBuilder.header("some-header", "true"); Response response = invocationBuilder.get(); System.out.println(response.getStatus()); System.out.println(response.readEntity(String.class)); 流式API Client client = ClientBuilder.newClient(new ClientConfig() .register(MyClientResponseFilter.class) .register(new AnotherClientFilter())); String entity = client.target("http://example.com/rest") .register(FilterForExampleCom.class) .path("resource/helloworld") .queryParam("greeting", "Hi World!") .request(MediaType.TEXT_PLAIN_TYPE) .header("some-header", "true") .get(String.class);

从上述的api可以看到jersey同样也要满足一个http call 的基本需求

URL Path header content-type accept cookie cachecontrol truststore Response MediaType parameter Method Response Entity Type

一些插入点,这些在后面会详细介绍,可以通过ClientConfig,Client,WebTarget 来注册。

Providers filters

下面是Client 的类图。 从这个类图上看, 其实这个client 被归为三部分

WebTarget 包括了Client级别的参数,URL, Path,URL Parameter Invocation builder 设定request 级别的参数 header, accept, cookie,content-type ,cache-control ... Invocation 则要处理响应的http method 和 request response 的处理。 image.png

下面是进行http call 的步骤。

Creating and configuring a Client instance

JAX-RS Client API 支持流式编程,这就意味着一个Client 构建出来后,从WebTarget 到 Invocation 的构建都可以通过流式API 来build. Client 从ClientBuilder开始。

Client client = ClientBuilder.newClient();

ClientBuilder 是个 JAX-RS API,用来创建Client instance. 当然ClientBuilder 能够利用ClientConfig 来进行property配置,例如SSL 设定。ClientConfig 实现了 Configurable 接口。因此Clientconfig 能够注册 providers (e.g. features or individual entity providers, filters or interceptors) 及设置属性。 下面是sample 代码:

ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MyClientResponseFilter.class); clientConfig.register(new AnotherClientFilter()); Client client = ClientBuilder.newClient(clientConfig);

在这个sample里, filter利用 ClientConfig.register(...) 方法来注册。这个方法可以注册feature(filter,provider, intercepter的集合),或者provider,filter, interceptor。 ClientConfig是负责创造一个client level 的配置。

除了API显示调用,Jersey 也支持流式API。 请看下面的例子:

Client client = ClientBuilder.newClient(new ClientConfig()) .register(MyClientResponseFilter.class) .register(new AnotherClientFilter());

由于Client 也实现了 Configurable接口,它支持在client实例创建后的继续配置。 Client端的配置变化不会影响到原始的ClientConfig, 它在ClientBuilder.newClient(new ClientConfig())时,从传入的config复制了一份。 下面的代码显示了Client 如何注册filter。

client.register(ThirdClientFilter.class);

同理, 由于 Client.register(...) method 支持流式API, 多个注册类型可以用下面类似代码注册:

client.register(FilterA.class) .register(new FilterB()) .property("my-property", true);

可以通过 Client instance a getConfiguration() 方法来获得当前的configuration。

ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MyClientResponseFilter.class); clientConfig.register(new AnotherClientFilter()); Client client = ClientBuilder.newClient(clientConfig); client.register(ThirdClientFilter.class); Configuration newConfiguration = client.getConfiguration();

在上面的代码中, MyClientResponseFilter class 和 AnotherClientFilter instance 由clientConfig注册。这个 clientConfig 用来创建 Client instance。 ThirdClientFilter 被Client instance注册。 在clientConfig里是发现不了ThirdClientFilter的。client的config 会依据clientConfig clone 一份,这个configuration 包含所有注册的3个 filters ,而开始的clientConfig 只包含两个filter。 client 里面的configuration对象 代表了Client里面的配置,client之后调用API进行的configuration操作都会反映到client configuration 对象中。 这个configuration 对象是client 配置的真实状态。这样的配置隔离是非常必要的。

你可以用复用同样的clientConfig 来配置多个client instance。 一个client instance 来进行多次配置,也不需要考虑对初始的 clientConfig带来一些不可以预估的影响。 Build WebTarget

下面在用client 创建一个webTaret。

WebTarget webTarget = client.target("http://example.com/rest"); webTarget.register(FilterForExampleCom.class);

所有的参数都可以在ClientConfig里定义。当然对于参数也可以在相关的地方用API输入。对于第三方的Filer,provider, 只要是实现了Configurable接口的 都可以注册,只是Client 和WebTarget的注册方法的scope 有所不同。在Client 或者ClientConfig注册的,filter,provider的scope 是client, 而在webTarget注册的,filter,provider的scope 是webTarget。 如果Client 注册了另外一个WebTarget,那么在原来webTarget 注册的filter, provider 就不起作用了。

Identifying resource on WebTarget

假设一个webTarget 指向 "http://example.com/rest", 这个URI 有一个Resource "http://example.com/rest/resource". 一个WebTarget 能够从另外一个webTarget继承过来。

WebTarget resourceWebTarget = webTarget.path("resource");

上面代码后, resourceWebTarget 现在指向URI "http://example.com/rest/resource"。 如果为resourceWebTarget 配置了一个 filter FilterForExampleCom, 不会影响原来的webTarget 变量.。但是filter FilterForExampleCom 会从webTarget被resourceWebTarget 继承过来。这样可以支持公用的配置,并且进行客制化。

在举个例子,假定再有个URI 是"http://example.com/rest/resource/helloworld"。代码可以如下:

WebTarget helloworldWebTarget = resourceWebTarget.path("helloworld");

在假定需要传入一下request 参数,代码可以如下,同样道理,这些request 参数也是可以集成的。

WebTarget helloworldWebTargetWithQueryParam =helloworldWebTarget.queryParam("greeting", "Hi World!"); Invoking a HTTP request

创建了 web targets后,要用webTarget创建Invocation.Builder 从而创建一个HTTP request 的调用。

Invocation.Builder invocationBuilder =helloworldWebTargetWithQueryParam.request(MediaType.TEXT_PLAIN_TYPE); invocationBuilder.header("some-header", "true");

一个 invocation builder instance 可以用webTarget的 request(...) 方法来创建. 方法的参数定义返回的 media type. 例子是传递了一个"text/plain" 类型. 这就相当于在header里设定 Accept: text/plain 。 invocationBuilder 用来设定request 级别的参数. 例如设置各种header,在本例里设置了key为"some-header" header 为true。

在这个过程中,InvocationBuilderListener 在request 方法结束的时候会被调用

public JerseyInvocation.Builder request() { checkNotClosed(); JerseyInvocation.Builder b = new JerseyInvocation.Builder(getUri(), config.snapshot()); return onBuilder(b); } private static JerseyInvocation.Builder onBuilder(JerseyInvocation.Builder builder) { new InvocationBuilderListenerStage(builder.request().getInjectionManager()).invokeListener(builder); return builder; } /* package */ class InvocationBuilderListenerStage { final Iterator invocationBuilderListenerIterator; /* package */ InvocationBuilderListenerStage(InjectionManager injectionManager) { final RankedComparator comparator = new RankedComparator(RankedComparator.Order.ASCENDING); invocationBuilderListenerIterator = Providers .getAllProviders(injectionManager, InvocationBuilderListener.class, comparator).iterator(); } /* package */ void invokeListener(JerseyInvocation.Builder builder) { while (invocationBuilderListenerIterator.hasNext()) { invocationBuilderListenerIterator.next().onNewBuilder(new InvocationBuilderContextImpl(builder)); } }

在InvocationBuilderListener, 可以做一些request build 的check 或者 设置 比如header MY_HEADER 是必须要设置的,可以缺省设置

public static class MyFeature implements Feature { @Override public boolean configure(FeatureContext context) { context.register( (InvocationBuilderListener)(l)-> l.getHeaders().add("MY_HEADER", "MY_VALUE") ); return true; } }

完成了request的设定后,就可以进行http request调用了。目前有两个方法

可以使用 Invocation.Builder生成一个Invocation 对象. 使用 Invocation 可以设定额外的request properties 例如 HTTP 的方法, 特别的property等。 任何设置在invocation对象的properties 都能在request 的处理过程中被读取。 例如, 在一个ClientRequestFilter 调用getProperty() 方法从 ClientRequestContext 读到一个设定的property。

这里的invocation properties 和继承于 Configurable接口的property不同。 Invocation instance 提供调用http request 的 common 接口,可以是同步的,也可以是异步的。

下面代码真正调用了一个get 的http call。

Response response = invocationBuilder.get();

总结一下,这段代码有很多步骤

invocationBuilder build request。 The URI of request will be http://example.com/rest/resource/helloworld?greeting="Hi%20World!" 这个 request 包含 some-header: true 和 Accept: text/plain headers. -这个 request 将会经历所有的filter ( AnotherClientFilter, ThirdClientFilter and FilterForExampleCom). 经过filter之后, 这个 request 将会被发送到服务端。当服务端返回 一个HTTP 200的 a plain text response。 我们可以打印response 里面的值。 System.out.println(response.getStatus()); System.out.println(response.readEntity(String.class));

程序将输出:

200 Hi World!

我们可以看到,请求成功了(code 200) 并且返回了一个"Hi World!".

上文我们配置了 MyClientResponseFilter ,当 response.readEntity(String.class) 被调用时, response 将先进入到response filter chain 和 entity interceptor chain 。 它会寻找一个合适的 MessageBodyReader 讲response stream 解析成一个 a Java String.

下面是一个用post 的代码例子。

Response postResponse = helloworldWebTarget.request(MediaType.TEXT_PLAIN_TYPE) .post(Entity.entity("A string entity to be POSTed", MediaType.TEXT_PLAIN));

本章着重讲述了client api 和配置的层级关系。 对于如何调用, 如何返回,我们会在下一章介绍。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3