Tiven Wang
Wang Tiven August 07, 2017
425 favorite favorites
bookmark bookmark
share share

下載本文完整項目代碼 Github

同步執行任務就是你需要等待任務執行完成才能接著執行後續步驟,而異步執行則是你不需要等待任務執行完成就能繼續執行後續步驟。在計算機環境中異步任務會在另外的線程 Thread 裡執行。

對於 Restful API 來說,每個 HTTP Request 都有一個 Request 和 一個 Response。 套用同步和異步的概念則是,同步指你發送 Request 後 API 需要等待任務執行完成後返回給你 Response,異步指 API 不需要等待任務執行完成而返回空或者臨時值的 Response 給你。

舉個例子:英雄管理者告訴 server 要求 Hero “Batman” 去抓捕 Villains “X”,但管理者並不需要等待抓捕完成(或許他會通過其他方式得到通知,或者他後續會去查詢抓捕結果)

如何在 Java Servlet 裡實現異步操作有很多方式:

  • Servlet 3 request.startAsync()
  • Spring @Async
  • Send a event or message to event or message server

Spring Async

Async Class Method

新建 HeroService 它有一個抓捕壞蛋的方法 catchVillains:

@Service
public class HeroService {

  @Autowired VillainsRepository villainsRepository;

  @Async
  public CompletableFuture<BigInteger> catchVillains(Hero hero, String name) throws InterruptedException {
    Thread.sleep(3000L);
    Villains villains = new Villains(name);
    villains.setCatchedBy(hero);
    return CompletableFuture.completedFuture(villainsRepository.save(villains).getId());
  }
}

@Async 註解說明 method 或者 type 是異步操作,Spring 需要為其生成運行單獨線程的 proxy class。

@Async 的方法返回值需要特定類型,我們使用 CompletableFuture

Thread.sleep(3000L) 模擬抓捕線程需要運行3秒

Spring Configuration

在 Spring 配置類中添加註解 @EnableAsync 啟用 Spring 對 @Async 的支持。

@Configuration
@EnableAsync
public class AsyncConfiguration {

  @Bean
  public Executor asyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(2);
    executor.setMaxPoolSize(2);
    executor.setQueueCapacity(500);
    executor.setThreadNamePrefix("Hero-");
    executor.initialize();
    return executor;
  }
}

默認 Spring 使用 SimpleAsyncTaskExecutor 執行異步任務,你也可以配置自己的 Executor, 這裡我們使用 ThreadPoolTaskExecutor 並設並行運行線程個數最大為2,隊列容量最大500。

Controller

HeroController 新增一個抓捕的API,此方法返回類型為 void。 方法調用 HeroService 的 catchVillains 方法。

注意 這裡不要調用返回值 CompletableFutureget 方法獲取任務結果,那樣的話此 API 就仍然需要等待異步任務執行完成才返回 Response。因為我們想要的效果是不需要等待抓捕結果。

@RequestMapping(path="/{id}/catch/{villains}", method=RequestMethod.POST)
void catchVillains(@PathVariable("id") Hero hero, @PathVariable("villains") String villains) throws InterruptedException {
  heroService.catchVillains(hero, villains);
}

Test

利用以前得到的英雄的ID調用URL去告訴他去抓捕x壞蛋,可以看到調用並沒有耗時太多:

http://127.0.0.1:8090/hero/27710009554537466484656569850/catch/x

大體上3秒後查詢會得到結果;

http://127.0.0.1:8090/villains

Message Broker

如果你的應用程序架構使用了 Message Broker 處理消息的話,則可以在 Controller 裡發送一個消息給消息服務器,然後即可返回 Response。 消息接收方會處理相應的後續邏輯。

關於 Message Broker 的基本架構可以參考 Try Cloud Foundry 系列中的 Try Cloud Foundry 9 - Message Broker

Reactive Programming

TODO

References

Similar Posts

  • Microservices - API Gateway Implement an API gateway that is the single entry point for all clients. The API gateway handles requests in one of two ways. Some requests are simply proxied/routed to the appropriate service. It handles other requests by fanning out to multiple services.
  • Microservices - Circuit Breaker 访问远程服务时, 比依赖超时时间更好一些的方式是一种叫断路器(Circuit Breaker)的模式. Circuit Breaker 就像一位交通警察, 在前方道路畅通的情况下, 他会放行; 当前方道路由于各种原因拥堵时, 他会告诉你前方道路不通请回; 如果他是个更智能的交警的话, 还会告诉你前方道路部分拥堵, 只允许部分车辆通过, 比如实行单双号.
  • Microservices - Architecture Microservice architecture (MSA) is an approach to building software systems that decomposes business domain models into smaller, consistent, bounded-contexts implemented by services. These services are isolated and autonomous yet communicate to provide some piece of business functionality. Microservices are typically implemented and operated by small teams with enough autonomy that each team and service can change its internal implementation details (including replacing it outright!) with minimal impact across the rest of the system.
  • Microservices - Load Balancing 在微服务架构中每个服务都可能有多个运行实例, 那么服务消费者在调用服务时怎么定位应该把请求发送给哪个实例呐? 这就是负载均衡 Load Balancing 要做的事情。Load Balancing 可以在服务端也可以是在消费端。
  • Microservices - Service Discovery Clients of a service use either Client-side discovery or Server-side discovery to determine the location of a service instance to which to send requests. Why use Service Discovery?
  • Try Cloud Foundry 10 - Service Discovery Service Registry for Pivotal Cloud Foundry (PCF) provides your applications with an implementation of the Service Discovery pattern, one of the key tenets of a microservice-based architecture. Trying to hand-configure each client of a service or adopt some form of access convention can be difficult and prove to be brittle in production. Instead, your applications can use the Service Registry to dynamically discover and call registered services.

Comments

comments powered by Disqus
Back to Top