我正在开发一个 Web 应用程序,其中一个要求是调用一个外部 Web 服务,该服务是通过 Jersey 客户端完成的。现在我想在一个单独的线程中调用这个 Web 服务 api,这样 UI 就不会在等待 WS 响应时被阻塞。我还希望能够只记录 Web 服务调用返回的响应,并且不会在任何业务逻辑中使用该响应。为此,我创建了一个 spring 托管 bean,它将包含对 spring 的引用ThreadPoolTaskExecutor
。配置如下:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
<bean id="updateEmailSubscriptionClient" class="com.myorg.MyClass">
<constructor-arg ref="taskExecutor" />
</bean>
MyClass
有一个实现可运行的内部类,用于生成将执行实际 Web 服务调用并记录响应的线程,所有这些都是异步完成的,因此 UI 不会被阻塞。MyClass
看起来像这样:
public class MyClass {
private Client jClient; //The jersey client
private TaskExecutor taskExecutor;
public MyClass(TaskExecutor taskExecutor){
this.taskExecutor = taskExecutor;
ClientConfig cc = new DefaultClientConfig();
//Initialize jersey client config here ...
jClient = Client.create(cc);
}
public void makeWSCall(){
//Do some stuff
taskExecutor.execute(new WorkerClass());
}
private class WorkerClass implements Runnable{
void run(){
WebResource webResource = jClient.resource(myResource);
//Setup webresource here with headers, mime etc....
try{
String resp = webResource.post(String.class);
//Log the response here ...
}catch(UniformInterfaceException e){
//Do something ...
}
}
}
}
从上面的代码可以看出,尝试是将球衣客户端调用放到 WS 中实现的 run 方法中WorkerClass
。然后,Runnable
公共方法makeWSCall
将在调用时taskExecutor
执行一个新WorkerClass
对象。我的问题/担忧如下:
- 这是解决手头问题的好方法吗?对于使用我们公共领域网站的多个客户来说,它是否会表现良好?
- 我没有
taskExecutor
在 Spring 配置文件中给出任何销毁方法。有必要吗? - 如果 的
run()
方法WorkerClass
抛出异常会发生什么?该线程是否再次从池中可用? - 任何其他问题或更好的想法。
请注意,我尝试使用 Jersey'sAsyncWebResource
但我仍然必须从仍会阻止 UI 的帖子中返回的 Future 对象获取响应。此外,我们使用的是非常旧版本的 jersey 客户端 (1.0.2),其中一些较新的功能可能不可用。升级到较新版本目前超出了该项目的范围。
编辑
我在 Spring 中阅读了有关 @Async 注释的信息,我认为这比使用实现可运行的内部类更好。我认为解决方法是将代码传输WorkerClass
到中makeWSCall
,使用@Async 进行注释makeWSCall
,在 spring 配置文件中进行必要的更改。但是,如果在应用程序上下文中定义了另一个执行程序会发生什么。Spring 怎么知道在哪个执行程序中运行我的 @Async 方法?
编辑
我最终使用了 @Async 注释,它工作正常。另一个问题是关闭连接。返回响应后如何确保关闭连接。我可以调用确保连接关闭getEntity
的对象(根据球衣文档)。ClientResponse
但是,如果在我的网络资源上执行实际的发布请求时或什至出现异常getEntity
,连接是否仍会关闭,或者我是否必须明确执行?在我的球衣版本中,没有close()
. ClientResponse
我应该如何关闭异常连接?