java - How to send parallel GET requests and wait for result responses? -
i'm using apache http client within spring mvc 3.2.2 send 5 requests synchronously illustrated.
how can send of these asynchronously (in parallel) , wait requests return in order return parsed payload string requests?
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 work here...and wait requests return // parse info out of multiple requests , return string results = doworkwithmultipledatareturned(); model.addattribute(results, results); return "index"; }
just in general, need encapsulate units of work in runnable
or java.util.concurrent.callable
, execute them via java.util.concurrent.executor
(or org.springframework.core.task.taskexecutor
). allows each unit of work executed separately, typically in asynchronous fashion (depending on implementation of executor
).
so specific problem, this:
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 private executor executor; @requestmapping("/your/path/here") public string mymvccontrollergetdatamethod(model model) { //define async requests , give them 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 async tasks complete while(!tasks.isempty()) { for(iterator<getrequesttask> = tasks.iterator(); it.hasnext();) { getrequesttask task = it.next(); if(task.isdone()) { string request = task.getrequest(); string response = task.getresponse(); //put code here //possibly aggregate request , response in map<string,string> //or else request , response it.remove(); } } //avoid tight loop in "main" thread if(!tasks.isempty()) thread.sleep(100); } //now have responses async requests //the following original code //note: should pass responses above //to next method (to keep controller stateless) string results = doworkwithmultipledatareturned(); model.addattribute(results, results); return "index"; } //abstraction wrap callable , 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 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()); } } }
note code has not been tested.
for executor
implementation, check out spring's taskexecutor , task:executor namespace. want reusable pool of threads use-case (instead of creating new thread every time).
Comments
Post a Comment