在传统的同步 WebService 调用中,客户端发起请求后会一直阻塞,直到收到服务端的响应,如果服务端处理时间较长,客户端的线程就会被长时间占用,导致资源浪费和用户体验下降。

异步 WebService 调用则允许客户端在发送请求后立即释放线程,可以去执行其他任务,而不必等待服务端的响应,当服务端处理完成后,会通过某种回调机制将结果返回给客户端。
核心概念
- 异步非阻塞:客户端线程不等待,立即返回。
- 回调:这是异步模式的核心,客户端需要提供一个“回调地址”(Callback Address),服务端在处理完请求后,会主动向这个地址发送响应结果。
- Future/Promise 模式:客户端发起请求后,会立即收到一个“未来结果”的对象(如
java.util.concurrent.Future),客户端可以稍后通过这个对象去检查是否完成,并获取最终结果。
实现方式
在 Java 生态中,实现 WebService 异步调用主要有以下几种方式,它们分别对应不同的技术栈和时代:
JAX-WS (Java API for XML Web Services) - 标准方式
JAX-WS 是 Java 官方标准的 WebService 技术,它本身就内置了对异步调用的支持,它主要通过 Future 和 Callback 两种方式实现。
场景:假设我们有一个简单的 WebService
服务端接口 (HelloService)

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
// @WebService 表示这是一个 WebService 接口
@WebService
// @SOAPBinding 指定 SOAP 协议风格
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface HelloService {
// 同步方法
@WebMethod
String sayHello(String name);
// 异步方法,返回 Future
@WebMethod
java.util.concurrent.Future<String> sayHelloAsync(String name);
// 异步方法,使用回调
@WebMethod
void sayHelloAsync(String name, javax.xml.ws.AsyncHandler<java.lang.String> handler);
}
服务端实现 (HelloServiceImpl)
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.xml.ws.AsyncHandler;
@WebService(endpointInterface = "com.example.HelloService")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class HelloServiceImpl implements HelloService {
// 使用线程池来模拟耗时操作,避免阻塞服务端线程
private final ExecutorService executor = Executors.newCachedThreadPool();
@Override
public String sayHello(String name) {
System.out.println("同步方法被调用,线程: " + Thread.currentThread().getName());
try {
// 模拟耗时操作
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, " + name + " (同步调用)";
}
@Override
public Future<String> sayHelloAsync(String name) {
System.out.println("异步方法(Future)被调用,线程: " + Thread.currentThread().getName());
// 在后台线程中执行任务
AsyncHelloTask task = new AsyncHelloTask(name);
executor.execute(task);
return task;
}
@Override
public void sayHelloAsync(String name, AsyncHandler<String> handler) {
System.out.println("异步方法(Callback)被调用,线程: " + Thread.currentThread().getName());
// 在后台线程中执行任务,完成后调用 handler
executor.execute(() -> {
try {
Thread.sleep(3000);
String result = "Hello, " + name + " (异步回调)";
System.out.println("任务完成,准备回调...");
// 处理完成,调用 handleResponse 方法
handler.handleResponse(new javax.xml.ws.Response<>(result, null));
} catch (Exception e) {
e.printStackTrace();
}
});
}
// 用于 Future 方式的内部任务类
private static class AsyncHelloTask implements Future<String> {
private String name;
private volatile boolean isDone = false;
private volatile String result;
private volatile Exception exception;
public AsyncHelloTask(String name) {
this.name = name;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return isDone;
}
@Override
public String get() throws InterruptedException, java.util.concurrent.ExecutionException {
// 如果任务没完成,当前线程会等待
while (!isDone) {
Thread.sleep(100);
}
if (exception != null) {
throw new java.util.concurrent.ExecutionException(exception);
}
return result;
}
@Override
public String get(long timeout, java.util.concurrent.TimeUnit unit)
throws InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException {
// 带超时的等待
long endTime = System.currentTimeMillis() + unit.toMillis(timeout);
while (!isDone && System.currentTimeMillis() < endTime) {
Thread.sleep(100);
}
if (!isDone) {
throw new java.util.concurrent.TimeoutException();
}
if (exception != null) {
throw new java.util.concurrent.ExecutionException(exception);
}
return result;
}
public void setResult(String result) {
this.result = result;
this.isDone = true;
}
}
}
客户端调用示例
import javax.xml.namespace.QName;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPFaultException;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutionException;
public class JAXWSAsyncClient {
public static void main(String[] args) {
try {
// 1. 创建 Service 实例 (wsimport 生成的代码会简化这一步)
URL wsdlUrl = new URL("http://localhost:8080/HelloService?wsdl");
QName qname = new QName("http://example.com/", "HelloServiceService");
Service service = Service.create(wsdlUrl, qname);
HelloService helloService = service.getPort(HelloService.class);
System.out.println("--- 开始异步调用 (Future 方式) ---");
// Future 方式
Future<String> futureResult = helloService.sayHelloAsync("Future User");
// 在等待结果期间,客户端可以做其他事情
System.out.println("请求已发送,客户端线程未被阻塞,可以继续做其他工作...");
for (int i = 0; i < 5; i++) {
System.out.println("客户端正在执行其他任务... " + i);
Thread.sleep(500);
}
// 获取结果,如果结果未准备好,这里会阻塞
String resultFromFuture = futureResult.get();
System.out.println("Future 方式收到结果: " + resultFromFuture);
System.out.println("\n--- 开始异步调用 (Callback 方式) ---");
// Callback 方式
helloService.sayHelloAsync("Callback User", new AsyncHandler<String>() {
@Override
public void handleResponse(Response<String> response) {
try {
String result = response.get();
System.out.println("Callback 方式收到结果: " + result);
} catch (Exception e) {
e.printStackTrace();
}
}
});
System.out.println("Callback 请求已发送,客户端线程未被阻塞...");
// 主线程需要保持存活,否则回调可能无法执行
// 在真实应用中,主线程可能是一个 Web 容器或消息监听器
Thread.sleep(5000); // 等待回调完成
} catch (Exception e) {
e.printStackTrace();
}
}
}
JAX-WS 异步总结:
- 优点: 是 Java 标准的一部分,无需额外依赖。
- 缺点: 配置和代码相对繁琐,回调处理需要手动实现。
wsimport工具会生成客户端辅助类,简化部分工作,但底层逻辑依然如此。
Spring Boot + Spring WebService - 现代方式
Spring 对 JAX-WS 和 JAX-RS 都提供了优秀的支持,使得异步调用变得更加简洁和现代化。

场景:基于 Spring Boot 的异步 WebService
服务端 (使用 @Async)
Spring 的 @Async 注解是实现异步调用的利器。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.jws.WebService;
import java.util.concurrent.Executor;
@SpringBootApplication
@EnableAsync // 启用异步方法支持
public class SpringWsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringWsApplication.class, args);
}
// 配置一个线程池用于异步任务
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("WsAsync-");
executor.initialize();
return executor;
}
}
// WebService 接口
import org.springframework.scheduling.annotation.Async;
@WebService
public interface SpringHelloService {
String sayHello(String name);
// 使用 @Async 注解,Spring 会自动在后台线程中执行此方法
@Async
String sayHelloAsync(String name);
}
// WebService 实现
import org.springframework.stereotype.Service;
@Service
@WebService(serviceName = "SpringHelloService", endpointInterface = "com.example.SpringHelloService")
public class SpringHelloServiceImpl implements SpringHelloService {
@Override
public String sayHello(String name) {
System.out.println("同步调用: " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, " + name + " (Spring 同步)";
}
@Override
@Async
public String sayHelloAsync(String name) {
System.out.println("异步调用: " + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, " + name + " (Spring 异步)";
}
}
客户端 (使用 WebTemplate)
Spring 提供了 WebTemplate(类似于 RestTemplate)来简化 WebService 调用。
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.client.core.SoapActionCallback;
@Configuration
public class WsClientConfig {
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// 需要指定服务端接口的包名
marshaller.setPackagesToScan("com.example");
return marshaller;
}
@Bean
public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marshaller) {
WebServiceTemplate template = new WebServiceTemplate(marshaller);
template.setDefaultUri("http://localhost:8080/ws/springHelloService");
return template;
}
@Bean
public CommandLineRunner run(WebServiceTemplate webServiceTemplate) {
return args -> {
System.out.println("--- Spring WebService 异步调用 ---");
// 同步调用
// String response = (String) webServiceTemplate.marshalSendAndReceive("World", new SoapActionCallback(""));
// 异步调用
// 发送请求并立即返回一个 Future 对象
java.util.concurrent.Future<Object> future = webServiceTemplate.sendAndReceive(
"World",
message -> {
message.setSoapAction("http://example.com/springHelloService/sayHelloAsync");
// 这里可以设置请求体
},
response -> {
// 这里是响应回调,可以处理响应
return response.getPayload(); // 返回响应结果
}
);
System.out.println("Spring 异步请求已发送,客户端未被阻塞...");
// 可以做其他事情...
for (int i = 0; i < 3; i++) {
System.out.println("客户端忙于其他事务...");
Thread.sleep(500);
}
// 获取结果
try {
String result = (String) future.get();
System.out.println("Spring 异步调用收到结果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
};
}
}
Spring WebService 异步总结:
- 优点: 与 Spring 生态系统无缝集成,代码更简洁,通过
@Async和线程池配置,管理非常方便。 - 缺点: 需要 Spring Boot 环境,对于轻量级应用可能显得过重。
JAX-RS (Java API for RESTful Web Services) - REST API 方式
对于 RESTful API,异步调用是现代 Web 应用的标配,通常使用 CompletableFuture 和响应式编程(如 Project Reactor, RxJava)来实现。
场景:Spring Boot + JAX-RS (例如使用 Jersey 或 RESTEasy)
服务端 (返回 CompletableFuture)
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@RestController
public class AsyncResourceController {
private final Executor executor = Executors.newFixedThreadPool(10);
@GetMapping("/sync/hello/{name}")
public String sayHelloSync(@PathVariable String name) throws InterruptedException {
Thread.sleep(3000);
return "Hello, " + name + " (REST 同步)";
}
@GetMapping("/async/hello/{name}")
public CompletableFuture<String> sayHelloAsync(@PathVariable String name) {
System.out.println("接收到请求,线程: " + Thread.currentThread().getName());
// 将耗时任务提交到线程池,并返回一个 CompletableFuture
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Hello, " + name + " (REST 异步)";
}, executor);
}
}
客户端 (使用 WebClient)
Spring 的 WebClient 是进行异步 HTTP 请求的现代推荐方式。
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@Configuration
public class WebClientConfig {
@Bean
public CommandLineRunner run(WebClient.Builder builder) {
return args -> {
WebClient webClient = builder.baseUrl("http://localhost:8080").build();
System.out.println("--- REST API 异步调用 ---");
// 异步调用
Mono<String> asyncResponse = webClient.get()
.uri("/async/hello/WebClientUser")
.retrieve()
.bodyToMono(String.class);
System.out.println("REST 异步请求已发送...");
// 订阅结果,当结果到达时执行
asyncResponse.subscribe(
result -> System.out.println("收到异步结果: " + result),
error -> System.err.println("发生错误: " + error.getMessage())
);
System.out.println("客户端可以继续执行其他逻辑...");
// 主线程不等待
};
}
}
JAX-RS 异步总结:
- 优点: RESTful API 的标准异步实践,性能高,非阻塞(如果使用响应式编程如 WebFlux),是现代微服务架构的首选。
- 缺点: 主要用于 REST API,不适用于传统的 SOAP WebService。
总结与对比
| 特性 | JAX-WS (标准) | Spring WebService | JAX-RS (REST) |
|---|---|---|---|
| 技术类型 | SOAP | SOAP | REST |
| 异步实现 | Future<T>, AsyncHandler<T> |
@Async, WebServiceTemplate (Future/Promise) |
CompletableFuture<T>, Reactive (Mono/Flux) |
| 易用性 | 较低,代码繁琐 | 高,与 Spring 生态集成 | 高,现代 API 设计 |
| 性能 | 受限于线程池模型 | 受限于线程池模型 | 非阻塞模型,性能极高 |
| 适用场景 | 遗留系统、需要严格 SOAP 协议的企业集成 | 基于 Spring 的 SOAP 服务开发 | 现代微服务、高并发 REST API |
| 依赖 | JDK 内置 | Spring Framework | Spring Boot / Jersey / RESTEasy |
如何选择?
- 如果你在维护一个旧的 SOAP 项目,并且需要添加异步功能,JAX-WS 是你的不二之选。
- 如果你的新项目基于 Spring 生态,并且需要构建 SOAP 服务,使用 Spring WebService 会让你事半功倍。
- 如果你在构建新的、高性能的、现代化的微服务,JAX-RS (REST) 是绝对的主流和最佳实践,特别是结合响应式编程时。
