我在
spring mvc 3.2.2中使用apache http客户端,如图所示同步发送5个get请求.
如何异步(并行)发送所有这些异常并等待请求返回,以便从所有GET请求返回解析的有效负载字符串?
public String myMVCControllerGETdataMethod() { // Send 1st request HttpClient httpclient = new DefaultHttpClient(); HttpGet httpget = new HttpGet("http://api/data?type=1"); ResponseHandler<String> responseHandler = new BasicResponseHandler(); String responseBody = httpclient.execute(httpget,responseHandler); // Send 2st request HttpClient httpclient2 = new DefaultHttpClient(); HttpGet httpget2 = new HttpGet("http://api/data?type=2"); ResponseHandler2<String> responseHandler2 = new BasicResponseHandler(); String responseBody2 = httpclient.execute(httpget,responseHandler2); // o o o more gets here // Perform some work here...and wait for all requests to return // Parse info out of multiple requests and return String results = doWorkwithMultipleDataReturned(); model.addAttribute(results,results); return "index"; }
解决方法
通常,您需要将您的工作单元封装在Runnable或java.util.concurrent.Callable中,并通过java.util.concurrent.Executor(或org.springframework.core.task.TaskExecutor)执行它们.这允许每个单元的工作单独执行,通常以异步方式执行(取决于执行程序的实现).
所以对于你的具体问题,你可以这样做:
import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.FutureTask; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class MyController { //inject this private Executor executor; @RequestMapping("/your/path/here") public String myMVCControllerGETdataMethod(Model model) { //define all async requests and give them to injected Executor List<GetRequestTask> tasks = new ArrayList<GetRequestTask>(); tasks.add(new GetRequestTask("http://api/data?type=1",this.executor)); tasks.add(new GetRequestTask("http://api/data?type=2",this.executor)); //... //do other work here //... //now wait for all async tasks to complete while(!tasks.isEmpty()) { for(Iterator<GetRequestTask> it = tasks.iterator(); it.hasNext();) { GetRequestTask task = it.next(); if(task.isDone()) { String request = task.getRequest(); String response = task.getResponse(); //PUT YOUR CODE HERE //possibly aggregate request and response in Map<String,String> //or do something else with request and response it.remove(); } } //avoid tight loop in "main" thread if(!tasks.isEmpty()) Thread.sleep(100); } //now you have all responses for all async requests //the following from your original code //note: you should probably pass the responses from above //to this next method (to keep your controller stateless) String results = doWorkwithMultipleDataReturned(); model.addAttribute(results,results); return "index"; } //abstraction to wrap Callable and Future class GetRequestTask { private GetRequestWork work; private FutureTask<String> task; public GetRequestTask(String url,Executor executor) { this.work = new GetRequestWork(url); this.task = new FutureTask<String>(work); executor.execute(this.task); } public String getRequest() { return this.work.getUrl(); } public boolean isDone() { return this.task.isDone(); } public String getResponse() { try { return this.task.get(); } catch(Exception e) { throw new RuntimeException(e); } } } //Callable representing actual HTTP GET request class GetRequestWork implements Callable<String> { private final String url; public GetRequestWork(String url) { this.url = url; } public String getUrl() { return this.url; } public String call() throws Exception { return new DefaultHttpClient().execute(new HttpGet(getUrl()),new BasicResponseHandler()); } } }
请注意,此代码尚未测试.
对于您的Executor实现,请查看Spring’s TaskExecutor和task:executor namespace.您可能需要一个可重用的线程池用于此用例(而不是每次都创建一个新线程).