问题
I need to call a WS that has very large response times (seconds) - without any polling/callback mechanism implemented on their side.
I think the most effective way of doing this is using non-blocking io and some kind of callback mechanism when the response received. Since we mostly use Spring and CXF I started a proof-of concept project to test my concept and the configuration itself.
Fortunately there is an HttpAsyncClient for cxf and there are good tutorials how to configure it. But at some point I stucked: with sync mode it is ok, but when I want to use the callback, it thorows the following exception:
javax.xml.ws.WebServiceException: Could not find wsdl:binding operation info for web method getDataFromWebServiceAsync.
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:126)
at com.sun.proxy.$Proxy46.getDataFromWebServiceAsync(Unknown Source)
ws interface:
@WebService
public interface SampleWebService {
public Person getDataFromWebService(@WebParam String id);
public Future<?> getDataFromWebServiceAsync(@WebParam String id, @WebParam(name = "asyncHandler", targetNamespace = "") AsyncHandler<Person> asyncHandler);
}
client side test (implemented as a TestNG test):
@Test(threadPoolSize = 5, invocationCount = 100)
public void testMultithreadedNonBlockingSampleWs()
throws InterruptedException, ExecutionException {
client.getDataFromWebServiceAsync("" + id.getAndIncrement(),
new AsyncHandler<Person>() {
@Override
public void handleResponse(Response<Person> resp) {
Person person;
try {
person = resp.get();
log.info(person.getName() + " | " + person.getAge()
+ " | " + person.getDescription());
Assert.assertNotNull(person);
Assert.assertNotNull(person.getName());
} catch (InterruptedException | ExecutionException e) {
log.error("EXCEPTION WHILE PROCESSING RESPONSE CALLBACK");
e.printStackTrace();
}
}
});
}
server-side spring congfiguration:
<jaxws:endpoint id="sampleService"
implementor="my.sample.SampleWebServiceImpl" address="/SampleWebService" />
client-side spring configuration:
<jaxws:client id="client"
serviceClass="my.sample.SampleWebService"
address="http://localhost:8080/sample-ws-cxf/SampleWebService">
<jaxws:properties>
<entry key="javax.xml.ws.client.connectionTimeout" value="10" />
<entry key="javax.xml.ws.client.receiveTimeout" value="11000" />
<entry key="org.apache.cxf.transport.http.async.usePolicy" value="ALWAYS" />
<entry key="org.apache.cxf.transport.http.async.ioThreadCount" value="2" />
</jaxws:properties>
</jaxws:client>
From the articles I found it is not clear whether this (non-blocking callback) is really possible or only the polling/callback mechanism should work. Only this article states that: http://czechscala.wordpress.com/2013/05/13/non-blocking-soap-web-services-invocation/
Could anybody provide me clarification at this point? Any way of achieving this? Or any solution to handle long-running WS calls in a reasonable way?
回答1:
If I generate the interfaces out of wsdl using the '-asyncMethods' parameter, everything is fine! The main difference is that it generates a wrapper object around my Person object called GetDataFromWebServiceResponse. Now everything is fine: the server is called through the normal interface (no polling/callback implemented), but on client side the callback method is called upon response.
Working pom.xml particle:
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${full.path.to.generate.classes}</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${full.path.to.wsdl}</wsdl>
<extraargs>
<extraarg>-p</extraarg>
<extraarg>${package.name}</extraarg>
<extraarg>-asyncMethods</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
</execution>
I would suggest using cxf above 2.7.
Now I'm wondering how could anybody force calling the poll/callback style service methods from client side.... but that would be another story :-)
来源:https://stackoverflow.com/questions/25241712/non-blocking-ws-call-with-cxf