1. 概述

JDeferred 是一个轻量级 Java 库(也支持 Groovy),专门用于实现异步编程,让你告别样板代码。这个框架的设计灵感来源于 jQuery 的 Promise/Ajax 特性和 Android 的 Deferred Object 模式。

本文将带你深入了解 JDeferred 的核心功能和实用技巧。

2. Maven 依赖

在项目中集成 JDeferred 非常简单,只需在 pom.xml 中添加以下依赖:

<dependency>
    <groupId>org.jdeferred</groupId>
    <artifactId>jdeferred-core</artifactId>
    <version>1.2.6</version>
</dependency>

⚠️ 最新版本请查阅 Maven 中央仓库

3. Promise 核心机制

假设我们需要调用一个可能出错的同步 REST API,并根据返回结果执行不同操作。在 jQuery 中,我们可以这样写:

$.ajax("/GetEmployees")
    .done(function() { alert("success"); })
    .fail(function() { alert("error"); })
    .always(function() { alert("complete"); });

JDeferred 提供了类似的 PromiseDeferred 接口,通过线程无关的钩子机制实现状态驱动的异步流程:

Deferred<String, String, String> deferred = new DeferredObject<>();
Promise<String, String, String> promise = deferred.promise();

promise.done(result -> System.out.println("Job done"))
       .fail(rejection -> System.out.println("Job fail"))
       .progress(progress -> System.out.println("Job is in progress"))
       .always((state, result, rejection) -> 
           System.out.println("Job execution started"));

deferred.resolve("msg");
deferred.notify("notice");
deferred.reject("oops");

✅ 关键方法说明:

  • done():仅在任务成功完成时触发
  • fail():任务执行异常时触发
  • progress():任务开始执行时触发
  • always():无论任务状态如何都会触发

⚠️ 状态管理注意事项:

  • Deferred 对象有三种状态:PENDING/REJECTED/RESOLVED
  • 通过 deferred.state() 查询当前状态
  • 状态不可逆:一旦变为 RESOLVED 就不能 reject,变为 REJECTED 后不能 resolvenotify
  • 违反状态规则会抛出 IllegalStateException

4. 结果过滤器

在获取最终结果前,可以使用 DoneFilter 对结果进行预处理:

private static String modifiedMsg;

static String filter(String msg) {
    Deferred<String, ?, ?> d = new DeferredObject<>();
    Promise<String, ?, ?> p = d.promise();
    Promise<String, ?, ?> filtered = p.then((result) -> {
        modifiedMsg = "Hello " + result;
    });

    filtered.done(r -> System.out.println("filtering done"));

    d.resolve(msg);
    return modifiedMsg;
}

✅ 过滤器特点:

  • 线程安全的处理流程
  • 支持链式操作
  • 原始结果不会被修改

5. 管道处理器

DonePipe 提供更强大的后处理能力,支持基于结果的条件判断和状态转换:

public enum Result { 
    SUCCESS, FAILURE 
}; 

private static Result status; 

public static Result validate(int num) { 
    Deferred<Integer, ?, ?> d = new DeferredObject<>(); 
    Promise<Integer, ?, ?> p = d.promise(); 
    
    p.then((DonePipe<Integer, Integer, Exception, Void>) result -> {
        public Deferred<Integer, Exception, Void> pipeDone(Integer result) {
            if (result < 90) {
                return new DeferredObject<Integer, Exception, Void>()
                  .resolve(result);
            } else {
                return new DeferredObject<Integer, Exception, Void>()
                  .reject(new Exception("Unacceptable value"));
            }
    }).done(r -> status = Result.SUCCESS )
      .fail(r -> status = Result.FAILURE );

    d.resolve(num);
    return status;
}

⚠️ 实际使用时注意:

  • 管道处理可以改变后续流程的状态
  • 支持异常传播和自定义错误处理
  • 适合复杂的业务规则验证场景

6. Deferred 管理器

实际项目中常需处理多个异步任务,DeferredManager 提供统一管理能力:

Deferred<String, String, String> deferred = new DeferredObject<>();
DeferredManager dm = new DefaultDeferredManager();
Promise<String, String, String> p1 = deferred.promise(), 
  p2 = deferred.promise(), 
  p3 = deferred.promise();
dm.when(p1, p2, p3)
  .done(result -> ... )
  .fail(result -> ... );
deferred.resolve("Hello Baeldung");

✅ 高级特性:

  • 可绑定自定义线程池:
    ExecutorService executor = Executors.newFixedThreadPool(10);
    DeferredManager dm = new DefaultDeferredManager(executor);
    
  • 直接使用 Callable 简化代码:
    DeferredManager dm = new DefaultDeferredManager();
    dm.when(() -> {
        // 业务逻辑,抛出异常会中断任务
    }).done(result -> ... )
      .fail(e -> ... );
    

7. 线程安全等待

需要等待所有并行任务完成时,有两种安全方式:

方式一:同步等待(需手动同步)

DeferredManager dm = new DefaultDeferredManager();
Deferred<String, String, String> deferred = new DeferredObject<>();
Promise<String, String, String> p1 = deferred.promise();
Promise<String, String, String> p = dm
  .when(p1)
  .done(result -> ... )
  .fail(result -> ... );

synchronized (p) {
    while (p.isPending()) {
        try {
            p.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

deferred.resolve("Hello Baeldung");

方式二:推荐的安全等待

try {
    p.waitSafely();
} catch (InterruptedException e) {
    e.printStackTrace();
}

✅ 最佳实践:

  • 优先使用 waitSafely(),无需手动同步
  • 避免在回调中执行耗时操作
  • 合理设置线程池大小防止资源耗尽

8. Android 集成

在 Android 项目中使用 JDeferred 需添加特定依赖:

APKLIB 构建方式

<dependency>
    <groupId>org.jdeferred</groupId>
    <artifactId>jdeferred-android</artifactId>
    <version>1.2.6</version>
    <type>apklib</type>
</dependency>

AAR 构建方式

<dependency>
    <groupId>org.jdeferred</groupId>
    <artifactId>jdeferred-android-aar</artifactId>
    <version>1.2.6</version>
    <type>aar</type>
</dependency>

⚠️ Android 特别注意:

  • 确保在主线程处理 UI 更新
  • 避免内存泄漏(及时清理回调)
  • 使用 DeferredManager 管理生命周期

9. 总结

JDeferred 通过简洁的 API 设计,让 Java 异步编程变得优雅高效。核心优势包括:

✅ 主要亮点:

  • 类似 jQuery 的链式调用风格
  • 强大的状态管理机制
  • 灵活的过滤和管道处理
  • 完善的多任务协调能力
  • 良好的线程安全设计

⚠️ 使用建议:

  • 复杂异步流程优先考虑 JDeferred
  • 避免过度嵌套回调(回调地狱)
  • 合理使用线程池资源
  • 注意异常传播和状态一致性

完整示例代码请查阅 GitHub 仓库


原始标题:Guide to JDeferred | Baeldung