成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如此強大的REST Client API為什么都不用?

開發 前端
JAX-RS(Java API for RESTful Web Services)是一個用于構建和管理 RESTful Web 服務的標準規范。JAX-RS 提供了一系列強大的功能,使得開發者可以輕松地創建、消費和管理 RESTful 服務。

1. 簡介

本篇文章我們將介紹JAX-RS,使用Client API實現REST API接口的調用。

JAX-RS(Java API for RESTful Web Services)是一個用于構建和管理 RESTful Web 服務的標準規范。JAX-RS 提供了一系列強大的功能,使得開發者可以輕松地創建、消費和管理 RESTful 服務。

我們可以通過JAX-RS API編寫REST接口(Spring對應的Controller接口),也可以使用其提供的Client API實現 REST接口的調用。如下,我們實現REST API的定義:

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
@Path("/users")
public class UserResource {
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public List<User> getUsers() {}
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  public void createUser(User user) {}
  @PUT
  @Path("/{id}")
  @Consumes(MediaType.APPLICATION_JSON)
  public void updateUser(@PathParam("id") int id, User user) {}
  @DELETE
  @Path("/{id}")
  public void deleteUser(@PathParam("id") int id) {}
}

與Spring MVC的Controller接口相比,除了注解不一樣也沒有什么區別了,但是這里的JAX-RS是 Jakarta EE 的一部分是標準。

本篇文章的重點是通過JAX-RS的Client API實現遠程接口的調用,所以上面對服務接口的實現有興趣的可以查看《jaxrs-2_1-final-spec.pdf》規范文檔。

既然有了這么多的方式調用,為什么還要使用JAX-RS呢?我們這里就與Spring的RestTemplate,WebClient進行對比。

  • 標準化和兼容性JAX-RS:作為 Jakarta EE 的標準規范,JAX-RS 具有廣泛的兼容性和標準化支持。這意味著無論你使用哪種 JAX-RS 實現(如 Jersey、RESTEasy),都具有一致的行為。RestTemplate:Spring 框架的一部分,主要用于 Spring 生態系統中的應用。雖然功能強大,但其使用限于 Spring 應用。WebClient:也是 Spring 框架的一部分,主要用于響應式編程。同樣,其使用限于 Spring 應用。
  • 易用性和靈活性JAX-RS:提供了一套簡潔且靈活的接口,使得開發者可以輕松構建復雜的 HTTP 請求。支持多種請求方法和響應處理方式,且與 JAX-RS 提供者無縫集成。RestTemplate:提供了豐富的模板方法,使得發送 HTTP 請求變得簡單。WebClient:支持響應式編程模型,提供了流式 API,使得異步和非阻塞操作更加自然和高效。但學習曲線較陡峭
  • 異步支持JAX-RS:支持異步請求,對于耗時的任務,提高應用性能和響應性。RestTemplate:主要支持同步操作,雖然可以通過 AsyncRestTemplate 實現異步請求,但已經不推薦使用,過時了。WebClient:天然支持異步和響應式編程,非常適合處理高并發和延遲敏感的應用。 

接下來,我們將詳細介紹JAX-RS 使用Client API實現三方接口的調用。

2. 實戰案例

2.1 準備三方接口

@GetMapping("/{id}")
public User queryUser(@PathVariable Long id) {
  return new User(id, "姓名 - " + new Random().nextInt(100000)) ;
}


@GetMapping("/header")
public String header(@RequestHeader("x-token") String token) {
  return token ;
}


@GetMapping("/exception")
public User exception(Long id, String name) {
  System.out.println(1 / 0) ;
  return new User(id, name) ;
}


@GetMapping("")
public List<User> queryUsers() throws Exception {
  TimeUnit.SECONDS.sleep(2);
  return List.of(
      new User(1L, "姓名 - " + new Random().nextInt(100000)),
      new User(2L, "姓名 - " + new Random().nextInt(100000)),
      new User(3L, "姓名 - " + new Random().nextInt(100000))) ;
}

上面定義了4個接口,接下來,我們將圍繞這4個接口講解JAX-RS Client API的各種使用方法。

2.2 基本使用

Response response = ClientBuilder.newClient()
      .target("http://localhost:9100/users/666")
      .request()
      .get() ;
String ret = response.readEntity(String.class) ;
System.out.println(ret) ;

輸出結果

{"id":666,"name":"姓名 - 57414"}

是不是非常的簡單?

2.3 注冊Provider(類型轉換器)

在上面的示例中,我們以String字符串的形式獲取到數據,那能不能以對象如User來獲取結果呢?當然可以,如下示例:

public class JSONToObjectReader implements MessageBodyReader<Object> {


  @Override
  public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return !type.isPrimitive() ;
  }


  @Override
  public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
      MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
      throws IOException, WebApplicationException {
    return new ObjectMapper().readValue(entityStream, type) ;
  }
}

這里,我們自定義了 MessageBodyReader 這樣我們就可以實現自己的邏輯如何進行數據的轉換了,我們這里直接將 Stream 通過Jackson轉換為對象。接下來就是將上面的轉換器進行注冊

Response response = ClientBuilder.newClient()
    // 注冊轉換器
    .register(JSONToObjectReader.class)
    // ...
User ret = response.readEntity(User.class) ;
System.out.println(ret) ;

其實上面的注冊我們還可以全局注冊,如下方式:

ClientBuilder builder = ClientBuilder.newBuilder() ;
builder.register(JSONToObjectReader.class);
Client client = builder.client() ;
// ...

這樣所有三方接口調用都通過該Client即可。

2.4 注冊Filter組件

如果你想在請求發送前進行修改請求數據,或者返回結果后進行相應的處理,那么你可以自定義ClientRequestFilter,ClientResponseFilter。

public class LoggingFilter implements ClientRequestFilter, ClientResponseFilter {


  private final Logger logger = LoggerFactory.getLogger(getClass()) ;
  
  @Override
  public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
    logger.info("已經得到響應結果, 響應header: {}", responseContext.getHeaders()) ;
  }


  @Override
  public void filter(ClientRequestContext requestContext) throws IOException {
    logger.info("準備發送請求, 請求Headers: {}", requestContext.getHeaders()) ;
    // 我們可以在這里進行修改請求的數據(你還可以修改請求的uri等)
    requestContext.getHeaders().replace("x-token", List.of("88888888888")) ;
  }
}

接下來,就是注冊該過濾器,與上面注冊轉換器是一樣的。

Response response = client
  .target("http://localhost:9100/users/header")
  .register(LoggingFilter.class)
  // ...

控制臺輸出

圖片圖片

2.5 定義組件順序

如上的示例,如果我們還有一個AuthFilter,希望AuthFilter先執行,那么我們就可以通過 @Provider 注解控制他們的執行順序。

@Priority(-1)
public class AuthFilter implements 
    ClientRequestFilter, ClientResponseFilter {}
    
@Priority(0)
public class LoggingFilter implements 
  ClientRequestFilter, ClientResponseFilter {}

運行結果

圖片圖片

2.6 異步調用

要使用異步調用,我們可以使用默認的線程池,也可以自定義線程池,如下自定義線程池。

int core = Runtime.getRuntime().availableProcessors() ;
ExecutorService executorService = new ThreadPoolExecutor(core, core, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100)) ;
// 配置異步線程池
ClientBuilder builder = ClientBuilder.newBuilder().executorService(executorService) ;
Client client = builder.build().register(JSONToObjectReader.class) ;


Future<User> future = client
  .target("http://localhost:9100/users/666")
  .request(MediaType.APPLICATION_JSON)
  // 設置異步調用
  .async()
  .get(new InvocationCallback<User>() {
    @Override
    public void completed(User response) {
      System.out.printf("%s - 請求完成: %s%n", Thread.currentThread().getName(), response) ;
    }
    @Override
    public void failed(Throwable throwable) {
      System.err.printf("請求失敗: %s%n", throwable.getMessage()) ;
    }
  }) ;
User ret = future.get() ;
System.out.printf("返回結果: %s%n", ret) ;

運行結果

pool-1-thread-1 - 請求完成: User [id=666, name=姓名 - 34158]
返回結果: User [id=666, name=姓名 - 34158]

大多數情況你可以直接在回調的completed方法中執行其它邏輯。

2.7 反應式支持

在上面的異步請求中,我們通過回調的機制來獲取結果。回調適用于簡單的場景,但在多個事件同時存在時,源代碼會變得更難理解。例如,當異步調用需要組合、合并或以任何方式操作時,這些場景可能導致回調嵌套在其他回調中,從而使代碼的可讀性大大降低——這種情況通常被稱為“回調地獄”,因為調用的嵌套性質。

為了提高可讀性并使程序員能夠更好地理解異步計算,Java 8 引入了一個新的接口 CompletionStage,該接口包含大量專門用于管理異步計算的方法。

JAX-RS 2.1 定義了一種新的調用者類型 RxInvoker,以及基于 Java 8 的 CompletionStage 類型的默認實現 CompletionStageRxInvoker。

CompletionStage<User> stage = ClientBuilder.newClient()
    .target("http://localhost:9100/users/666")
    .register(JSONToObjectReader.class)
    .request(MediaType.APPLICATION_JSON)
    .rx()
    .get(User.class) ;
stage.whenComplete((res, ex) -> {
  if (ex != null) {
    System.err.printf("發生錯誤: %s%n", ex.getMessage()) ;
  } else {
    System.out.println(res) ;
  }
}) ;

這里我們可以利用CompletionState完成更多復雜的操作。有關CompletionState更多的用法,查看下面這篇文章:

強大的異步任務處理類CompletableFuture使用詳解

2.8 更多的配置

如果你需要進行更多的精細配置,如:超時時間,我們可以通過如下的方式進行配置:

ClientBuilder builder = ClientBuilder.newBuilder() ;
builder.connectTimeout(1000, TimeUnit.MILLISECONDS) ;
builder.readTimeout(1000, TimeUnit.MILLISECONDS) ;
builder.register(JSONToObjectReader.class) ;
Client client = builder.build() ;
client.target("http://localhost:9100/users")
  .register(JSONToObjectReader.class)
  .request(MediaType.APPLICATION_JSON)
  .buildGet()
  .submit(new InvocationCallback<List<User>>() {
    @Override
    public void completed(List<User> response) {
      System.out.printf("返回結果: %s%n", response) ;
    }
    @Override
    public void failed(Throwable throwable) {
      System.err.printf("發生錯誤: %s%n", throwable.getMessage()) ;
    }
  }) ;

運行結果

發生錯誤: java.net.SocketTimeoutException: Read timed out

異常處理也是非常的便捷。

責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2020-05-29 17:21:33

神經網絡學習函數

2010-03-10 18:42:30

Python性能

2025-03-25 07:10:00

開發前端JavaScript

2025-02-12 12:00:00

前端try-catchJavaScrip

2025-04-08 07:30:00

前端開發JavaScript

2012-04-09 13:35:10

Instagram

2023-12-06 07:13:16

RESTAPI客戶端

2019-02-26 10:57:54

消息簽名算法

2021-09-06 08:59:00

程序員技能開發

2019-01-15 17:50:18

存儲技術容器

2020-09-25 08:10:55

Rust系統編程

2021-11-18 11:23:09

微信WhatsAppAPP

2023-06-06 09:03:06

InnodbMySQL

2022-06-01 23:27:38

區塊鏈加密貨幣數字資產

2020-06-02 19:14:59

Kubernetes容器開發

2020-11-05 10:50:09

物聯網數據技術

2017-07-26 10:21:46

DockerLinux容器

2014-12-19 09:59:50

代碼

2022-11-28 09:00:03

編程bug開發

2020-09-22 15:29:03

UnixC++C
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩在线不卡视频 | 国产免费视频 | 精品毛片在线观看 | 国产97色 | 在线成人 | 国产精品亚洲一区 | 中文字幕国产第一页 | 午夜99 | 国产精品久久久久久久免费大片 | 一区在线视频 | 日韩一区三区 | 欧美在线观看网站 | 91亚洲精选 | 国产第1页 | 亚洲日韩中文字幕 | 黄色av网站在线观看 | 在线看日韩 | 欧美视频在线免费 | h片在线看 | 玖玖玖在线观看 | 久久久91精品国产一区二区三区 | 亚洲精品乱码久久久久久按摩观 | 日韩毛片在线视频 | 亚洲久草| 精品成人免费一区二区在线播放 | 欧美日韩在线成人 | 男女黄网站 | 久久精品免费看 | 亚洲国产精品第一区二区 | 成人免费视频网址 | 国产91亚洲精品一区二区三区 | 亚洲一区二区电影网 | 日韩精品一区中文字幕 | 成人欧美一区二区三区黑人孕妇 | 亚洲第一女人av | 久久久激情 | 在线播放精品视频 | 亚洲欧美中文日韩在线v日本 | 欧美精品日韩精品国产精品 | 黄色片在线免费看 | 久久一 |