1 / 53

JAX-RS 2.0 : REST 式 Web 服务 API 中新增的和值得关注的功能

JAX-RS 2.0 : REST 式 Web 服务 API 中新增的和值得关注的功能. John Clingan Java EE 和 GlassFish 产品经理 john.clingan@oracle.com. JAX-RS 回顾 客户端 API 通用配置 异步处理 过滤器 / 拦截器 超媒体支持 服务器端内容协商. JAX-RS 2.0 中的新增功能. JAX-RS — 用于 REST 式服务的 Java API. 注解驱动的标准 API , 用于帮助开发人员 使用 Java 构建 REST 式 Web 服务

Download Presentation

JAX-RS 2.0 : REST 式 Web 服务 API 中新增的和值得关注的功能

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. JAX-RS 2.0:REST 式 Web 服务 API 中新增的和值得关注的功能 John Clingan Java EE 和 GlassFish 产品经理 john.clingan@oracle.com

  2. JAX-RS 回顾 • 客户端 API • 通用配置 • 异步处理 • 过滤器/拦截器 • 超媒体支持 • 服务器端内容协商 JAX-RS 2.0 中的新增功能

  3. JAX-RS — 用于 REST 式服务的 Java API 注解驱动的标准API, 用于帮助开发人员 使用 Java 构建 REST 式Web 服务 和客户端 • 基于 POJO 的资源类 • 以 HTTP 为中心的编程模型 • 实体格式独立性 • 容器独立性 • 包括在 Java EE 中

  4. JAX-RS 示例 ... @POST @Path("/withdrawal") @Consumes("text/plain") @Produces("application/json") public Money withdraw( @PathParam("card") String card, @QueryParam("pin") String pin, String amount) { return getMoney(card, pin, amount); } }

  5. JAX-RS 注解(续)

  6. JAX RS 2.0 客户端 API

  7. 客户端 API 动机 • HTTP 客户端库太低级 • 利用 JAX-RS 1.x API 中的提供商/概念 • 主要实现引入的专用 API

  8. 客户端 API // Get instance of Client Client client = ClientBuilder.newClient(); // Get account balance String bal = client.target("http://.../atm/{cardId}/balance") .resolveTemplate("cardId", "111122223333") .queryParam("pin", "9876") .request("text/plain").get(String.class);

  9. 客户端 API // Withdraw some money Moneymoney =client.target("http://.../atm/{cardId}/withdrawal") .resolveTemplate("cardId", "111122223333") .queryParam("pin", "9876") .request("application/json") .post(text("50.0"), Money.class);

  10. 客户端 API Invocationinvocation1 = client.target("http://.../atm/{cardId}/balance")… .request(“text/plain”).buildGet(); Invocationinvocation2 = client.target("http://.../atm/{cardId}/withdraw")… .request("application/json") .buildPost(text("50.0"));

  11. 客户端 API Collection<Invocation> invocations =Arrays.asList(inv1, inv2); Collection<Response> responses = Collections.transform( invocations, new F<Invocation, Response>() { public Responseapply(Invocationinvocation) { return invocation.invoke(); } });

  12. 客户端 API // Create client and register MyProvider1 Client client = ClientBuilder.newClient(); client.register(MyProvider1.class); // Create atm target; inherits MyProvider1 WebTargetatm = client.target("http://.../atm"); // Register MyProvider2 atm.register(MyProvider2.class); // Create balance target; inherits MyProvider1, MyProvider2 WebTarget balance = atm.path(”{cardId}/balance"); // Register MyProvider3 balance.register(MyProvider3.class);

  13. JAX RS 2.0通用配置

  14. 通用配置 — 动机 客户端 客户端 .register(JsonMessageBodyReader.class) .register(JsonMessageBodyWriter.class) .register(JsonpInterceptor.class) .property(“jsonp.callback.name”, “callback”) .property(“jsonp.callback.queryParam”, “true”) ...

  15. 通用配置 — 动机 服务器端 public class MyApp extends javax.ws.rs.core.Application { public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<…>(); ... classes.add(JsonMessageBodyReader.class); classes.add(JsonMessageBodyWriter.class); classes.add(JsonpInterceptor.class); ... return classes; } }

  16. 通用配置 — 解决方案 客户端 客户端 .register(JsonMessageBodyReader.class) .register(JsonMessageBodyWriter.class) .register(JsonpInterceptor.class) .property(“jsonp.callback.name”, “callback”) .property(“jsonp.callback.queryParam”, “true”) ... JsonFeaturejf= new JsonFeature().enableCallbackQueryParam(); client.register(jf);

  17. 通用配置 — 解决方案 服务器端 public Set<Class<?>>getClasses() { ... classes.add(JsonMessageBodyReader.class); classes.add(JsonMessageBodyWriter.class); classes.add(JsonpInterceptor.class); ... } public Set<Class<?>>getClasses() { ... classes.add(JsonFeature.class); ... }

  18. 通用配置 public interface Configurable { Configuration getConfiguration(); Configurable property(String name, Object value); Configurable register(...); } public interface Configuration { Set<Class> getClasses(); Map<Class,Integer> getContracts(Class componentClass); Set<Object> getInstances(); Map<String,Object> getProperties(); Object getProperty(String name); Collection<String> getPropertyNames(); boolean isEnabled(Feature feature); boolean isRegistered(Object component); ... }

  19. 通用配置 public interface Feature { boolean configure(FeatureContext context); }

  20. Feature 示例 public void JsonFeature implements Feature { public boolean configure(FeatureContext context) { context.register(JsonMessageBodyReader.class) .register(JsonMessageBodyWriter.class) .register(JsonpInterceptor.class) .property(CALLBACK_NAME, calbackName) .property(USE_QUERY_PARAM, useQueryParam); return true; } }

  21. 动态 Feature 仅服务器端 public interface DynamicFeature { void configure(ResourceInfo ri, FeatureContext context); } public interface ResourceInfo { Method getResourceMethod(); Class<?> getResourceClass(); }

  22. JAX RS 2.0异步处理

  23. 异步处理 • 服务器 API • 分流 I/O 容器线程 • 高效的异步事件处理 • 利用 Servlet 3.x 异步支持(如果可用) • 客户端 API • 异步的请求调用 API

  24. 异步处理 @Stateless @Path("/async/longRunning") public class MyResource { @GET @Asynchronous public void longRunningOp(@SuspendedAsyncResponse ar) { ar.setTimeoutHandler(new MyTimoutHandler()); ar.setTimeout(15, SECONDS); final String result = executeLongRunningOperation(); ar.resume(result); } }

  25. 异步处理:服务器端 public interface AsyncResponse { public void resume(Object/Throwable response); public void cancel(); public void cancel(int/Date retryAfter); public boolean isSuspended(); public boolean isCancelled(); public boolean isDone(); public void setTimeout(long time, TimeUnit unit); public void setTimeoutHandler(TimeoutHandler handler); public Collection<Class<?>> register(Class<?> callback); public Map<Class<?>,Collection<Class<?>>> register(Class<?> callback, Class<?>... callbacks); public Collection<Class<?>> register(Object callback); public Map<Class<?>,Collection<Class<?>>> register(Object callback, Object... callbacks); }

  26. 异步处理:服务器端 @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Suspended { } public interface TimeoutHandler { void handleTimeout(AsyncResponse asyncResponse); }

  27. 异步处理:服务器端 public interface CompletionCallback { public void onComplete(Throwable throwable); } public interface ConnectionCallback { public void onDisconnect(AsyncResponse disconnected); }

  28. 异步处理:客户端 WebTarget target = client.target("http://.../balance”)… // Start async call and register callback Future<?> handle = target.request().async().get( new InvocationCallback<String>() { void complete(String balance) { … } void failed(InvocationException e) { … } }); // After waiting for too long… if (!handle.isDone()) handle.cancel(true);

  29. JAX RS 2.0过滤器/拦截器

  30. 过滤器和拦截器 动机 • 定制 JAX-RS 请求/响应处理 • 用例:日志记录、压缩、安全性,等等 • 针对客户端和服务器 API 而引入 • 替换现有的专用支持

  31. 过滤器和拦截器 过滤每个传入/传出消息 • 非包装过滤器链 • 过滤器不直接调用链中的下一个过滤器 • 由 JAX-RS 运行时管理 • 每个过滤器决定是继续还是中断链 • 请求  请求 • ContainerRequestFilter, ClientRequestFilter • 响应  响应 • ContainerResponseFilter, ClientResponseFilter • 服务器端特性 • @PreMatching、DynamicFeature

  32. 过滤器和拦截器 日志记录过滤器示例 public class RequestLoggingFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext requestContext) { log(requestContext); // non-wrapping => returns without invoking the next filter } ... }

  33. 过滤器和拦截器 拦截实体提供者 • 只有当发生实体处理时才会调用 • 性能提升 • 包装拦截器链 • 每个拦截器都通过 context.proceed() 调用链中的下一个拦截器 • MessageBodyReader拦截器 • ReaderInterceptor接口 • MessageBodyWriter 拦截器 • WriterInterceptor接口

  34. 过滤器和拦截器 Gzip 读取器拦截器示例 public class GzipInterceptor implements ReaderInterceptor { @Override Object aroundReadFrom(ReaderInterceptorContext ctx) { InputStream old = ctx.getInputStream(); ctx.setInputStream(new GZIPInputStream(old)); // wrapping => invokes the next interceptor Object entity = ctx.proceed(); ctx.setInputStream(old); return entity; } }

  35. 传输 响应 过滤器和拦截器 … 写入器 拦截器 写入器 拦截器 MBW 网络 应用程序 … 请求 过滤器 过滤器 … 过滤器 过滤器 … MBR 读取器 拦截器 读取器 拦截器

  36. 过滤器和拦截器 … 读取器 拦截器 读取器 拦截器 MBR @PreMatching 网络 资源匹配 … 应用程序 请求 过滤器 过滤器 过滤器 请求 过滤器 … 过滤器 过滤器 响应 响应 过滤器 过滤器 … MBW 写入器 拦截器 写入器 拦截器

  37. 绑定和优先级 • 绑定 • 将过滤器和拦截器与资源方法相关联 • 服务器端概念 • 优先级 • 声明在执行链中的相对位置 • @Priority(int priority) • 过滤器和拦截器共有的概念

  38. 绑定 @NameBinding @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(value = RetentionPolicy.RUNTIME) public @interface Logged {} @Provider @Logged @Priority(USER) public class LoggingFilter implements ContainerRequestFilter, ContainerResponseFilter { … }

  39. 绑定 @Path("/greet/{name}") @Produces("text/plain") public class MyResourceClass { @Logged @GET public String hello(@PathParam("name") String name) { return "Hello " + name; } }

  40. DynamicFeature 示例 仅服务器端 public void SecurityFeature implements DynamicFeature { public boolean configure(ResourceInfo ri, FeatureContext context) { String[] roles = getRolesAllowed(ri); if (roles != null) { context.register(new RolesAllowedFilter(roles)); } } ... }

  41. JAX RS 2.0超媒体支持

  42. 超媒体支持 • REST 原则 • 标识符和链接 • HATEOAS(超媒体作为应用程序状态的引擎) • 链接类型: • 结构性链接 • 过渡性链接

  43. 超媒体支持 Link:<http://.../orders/1/ship>; rel=ship, <http://.../orders/1/cancel>; rel=cancel ... <order id="1"> <customer>http://.../customers/11</customer> <address>http://.../customers/11/address/1</address> <items> <item> <product>http://.../products/111</product> <quantity>2</quantity> </item> <items> ... </order>

  44. 超媒体 • Link和 LinkBuilder类 • RFC 5988:Web 链接 • 支持 ResponseBuilder和过滤器中的链接 • 过渡性链接(标头) • 支持手动结构性链接 • 通过 Link.JaxbAdapter和 Link.JaxbLink • 从客户端 API 中的链接创建资源目标

  45. 超媒体 // Producer API (server-side) Link self= Link.fromMethod(MyResource.class, ”handleGet”) .build(); Link update= Link.fromMethod(MyResource.class, “handlePost”) .rel(”update”) .build(); ... Response res = Response.ok(order) .link("http://.../orders/1/ship", "ship") .links(self, update) .build();

  46. 超媒体 Response order = client.target(…).request("application/xml").get(); // Consumer API (client-side) Link shipmentLink = order.getLink(“ship”); if (shipmentLink != null) { Response shipment = client.target(shipmentLink).post(null); … }

  47. JAX RS 2.0服务器端内容协商

  48. 服务器端内容协商 GET http://.../widgets2 Accept: text/*; q=1 … Path("widgets2") public class WidgetsResource2 { @GET @Produces("text/plain", "text/html") public Widgets getWidget() {...} }

  49. 服务器端内容协商 GET http://.../widgets2 Accept: text/*; q=1 … Path("widgets2") public class WidgetsResource2 { @GET @Produces("text/plain; qs=0.5", "text/html; qs=0.75") public Widgets getWidget() {...} }

More Related