Jersey Client 的API |
您所在的位置:网站首页 › 参数配置client › Jersey Client 的API |
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 instanceJAX-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 |