使用 JAXB 数据绑定的基于通用 CXF WSDL 的服务器
Generic CXF WSDL-based Server using JAXB databinding
我正在寻找将 CXF 作为 Web 服务实施提供者集成到应用程序中的解决方案。应用程序应该能够基于提供的 WSDL 文件以动态方式实现 Web 服务(这意味着 SEI 类 不可用)。由于应用程序通过自己的 servlet 管理 http 请求和 url 映射,因此使用标准 CXF servlet 发布端点是不可行的。另外,我想使用 JAXB 数据绑定。理想情况下,CXF 应该调用我的 Object invoke(String oper, Object... args)
来真正处理 Web 服务。总体而言,它应该看起来像动态客户端,但为服务器部分实现。
我已经设法使代码几乎可以正常工作,但遇到了一些我不明白的事情 - 稍后再说。
首先我将 WSDL 读入一个字符串并创建它的定义。定义预缓存在 wsdlManager 中,可以通过唯一引用访问。然后我创建 JaxWS 动态客户端并获取由 CXF 为其生成的 JAXB 数据绑定。
WSDLManager wsdlManager = serviceBus.getExtension(WSDLManager.class);
WSDLFactory wsdlFactory = wsdlManager.getWSDLFactory();
// Reader
WSDLReader reader = wsdlFactory.newWSDLReader();
reader.setFeature("javax.wsdl.verbose", true);
reader.setFeature("javax.wsdl.importDocuments", true);
Definition def = reader.readWSDL(null, TypeCast.getInputSource(wsdl)); // wsdl is a String containing wsdl definition
// Precache definition using listenerRef as unique identifier
wsdlManager.addDefinition(listenerRef, def);
String[] compileOptions = null;
// Create JAXWS dynamic client using precached address
Client client = createClient(listenerRef, simpleDataBinding, allowElementReferences, compileOptions);
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: service client is created succefully: " + listenerName);
EndpointInfo cei = client.getEndpoint().getEndpointInfo();
// Use JAXB generated databinding
DataBinding db = client.getEndpoint().getService().getDataBinding();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: databinding: " + db);
动态客户端的创建很简单
public Client createClient(String serviceDescription, boolean simpleDataBinding, boolean allowElementReferences, String[] schemaOptions) {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
ParentClassLoader dynaLoader = new ParentClassLoader();
JaxWsDynamicClientFactory dynamicClientFactory = JaxWsDynamicClientFactory.newInstance(serviceBus);
dynamicClientFactory.setSimpleBindingEnabled(simpleDataBinding);
dynamicClientFactory.setAllowElementReferences(allowElementReferences);
if (schemaOptions != null) {
dynamicClientFactory.setSchemaCompilerOptions(schemaOptions);
}
return dynamicClientFactory.createClient(serviceDescription, dynaLoader);
} catch (Throwable ex) {
Logger.error("WebServiceProcessor.createClient: exception is caught: " + ex, ex);
return null;
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
接下来,要创建服务器内容,需要声明一些助手 类
protected class MyWSDLServiceFactory extends WSDLServiceFactory {
public MyWSDLServiceFactory(Bus b, Definition d) {
super(b, d);
}
@Override
public Service create() {
Service svc = super.create();
// Post init
initializeDefaultInterceptors();
initializeDataBindings();
return svc;
}
}
public class MyInvoker extends AbstractInvoker {
protected final Object implementor = new Object();
public MyInvoker() {
}
@Override
public Object getServiceObject(Exchange context) {
return implementor;
}
protected void throwable() throws Exception {
}
@Override
public Object invoke(Exchange exchange, Object o) {
List<Object> params = null;
if (o instanceof List) {
params = CastUtils.cast((List<?>)o);
} else if (o != null) {
params = new MessageContentsList(o);
}
if (Logger.isTraceEnabled()) {
for (Object arg : params)
Logger.trace("MyInvoker.invoke: arg: " + arg);
}
// Method holding declararions of throwable exceptions
Method m = null;
try {
m = MsyInvoker.class.getMethod("throwable");
} catch (NoSuchMethodException ex) {
// Strange
}
return invoke(exchange, null, m, params);
}
@Override
protected Object performInvocation(Exchange exchange, Object serviceObject, Method m, Object[] paramArray) throws Exception {
Message inMessage = exchange.getInMessage();
BindingOperationInfo bop = exchange.getBindingOperationInfo();
String oper = bop.getName().getLocalPart();
// Process request
return processWebListenerRequest(oper, paramArray);
}
}
protected class MyDestinationFactory implements DestinationFactory {
protected final Set<String> prefixes = Collections.unmodifiableSet(new HashSet<String> (Arrays.asList("http://", "https://")));
@Override
public Destination getDestination(EndpointInfo ei, Bus bus) throws IOException {
return new MyDestination(ei, ei.getAddress());
}
@Override
public Set<String> getUriPrefixes() {
return prefixes;
}
@Override
public List<String> getTransportIds() {
return null;
}
}
protected class MyDestination extends ServletDestination {
public MyDestination(EndpointInfo ei, String path) throws IOException {
super(serviceBus, null, ei, path, false);
// Disable async support
isServlet3 = false;
}
@Override
protected void setupMessage(final Message inMessage, final ServletConfig config, final ServletContext context, final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
super.setupMessage(inMessage, config, context, req, resp);
}
@Override
protected String getBasePath(String contextPath) throws IOException {
if (endpointInfo.getAddress() == null) {
return "";
}
return endpointInfo.getAddress();
}
}
然后我们准备创建服务器:
MyWSDLServiceFactory sf = new MyWSDLServiceFactory(serviceBus, def);
sf.setAllowElementRefs(allowElementReferences);
sf.setDataBinding(db);
Service svc = sf.create();
// Clear cached definition
wsdlManager.removeDefinition(def);
svc.setInvoker(new MyInvoker());
// Create endpoints
for (ServiceInfo inf : svc.getServiceInfos()) {
for (EndpointInfo ei : inf.getEndpoints()) {
if (ei.getName().equals(cei.getName())) {
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: endpoint: " + ei.getName());
String addr = "/" + listenerRef;
try {
ei.setAddress(addr);
JaxWsEndpointImpl ep = new JaxWsEndpointImpl(serviceBus, svc, ei);
svc.getEndpoints().put(ei.getName(), ep);
ep.addHandlerInterceptors();
ep.getInInterceptors().add(new SoapUtil.SoapInLogger());
BindingFactoryManager bfm = serviceBus.getExtension(BindingFactoryManager.class);
// tried this but no effect
// ei.getBinding().setProperty("soap.force.doclit.bare", Boolean.TRUE);
String bindingId = ei.getBinding().getBindingId();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: binding id: " + bindingId);
BindingFactory bindingFactory = bfm.getBindingFactory(bindingId);
Server server = new ServerImpl(serviceBus, ep, new MyDestinationFactory(), bindingFactory);
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: starting server: " + ei.getName());
server.start();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: server is started: " + server.isStarted());
// Set reference
listeners.put(listenerRef, server); // Our map to keep web server listeners
} catch (EndpointException e) {
throw new ServiceConstructionException(e);
}
}
}
}
服务器调用看起来像
String address = "/" + listenerRef;
Server server = listeners.get(listenerRef); // Find our server listener in a map
if (server != null) {
Endpoint ep = server.getEndpoint();
EndpointInfo ei = ep.getEndpointInfo();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.invoke: endpoint: " + listenerName);
try {
AbstractHTTPDestination dest = (AbstractHTTPDestination) server.getDestination();
AsyncContext asyncCtx = requestContext.getAsyncContext();
HttpServletRequest req = (HttpServletRequest) asyncCtx.getRequest();
HttpServletResponse resp = (HttpServletResponse) asyncCtx.getResponse();
ServletContext sctx = req.getServletContext();
ServletConfig scfg = null;
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.invoke: destination resolved successfully: " + listenerName);
// Trigger CXF processing
dest.invoke(scfg, sctx, req, resp);
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.invoke: endpoint processed successfully: " + listenerName);
} catch (Exception ex) {
Logger.error("WebServiceProcessor.invoke: exception is caught: " + ex, ex);
}
}
正如我已经提到的,该解决方案几乎可以工作,我尝试使用 CXF 3.3 和我作为示例的一个 WSDL 对其进行测试 http://www.dneonline.com/calculator.asmx?WSDL。我设法使用 SoapUI 调用该服务并获得响应。但现在是奇怪的部分。当我用标准请求调用网络服务时
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<Add xmlns="http://tempuri.org/">
<intA>1</intA><intB>2</intB>
</Add>
</soap:Body>
</soap:Envelope>
它因解组错误而失败
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"http://tempuri.org/", local:"intA"). Expected elements are <{http://tempuri.org/}Add>,<{http://tempuri.org/}AddResponse>,<{http://tempuri.org/}Divide>,<{http://tempuri.org/}DivideResponse>,<{http://tempuri.org/}Multiply>,<{http://tempuri.org/}MultiplyResponse>,<{http://tempuri.org/}Subtract>,<{http://tempuri.org/}SubtractResponse>
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:932) ~[cxf-rt-databinding-jaxb-3.3.6.jar:3.3.6]
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:738) ~[cxf-rt-databinding-jaxb-3.3.6.jar:3.3.6]
at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:170) ~[cxf-rt-databinding-jaxb-3.3.6.jar:3.3.6]
at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.getPara(DocLiteralInInterceptor.java:325) ~[cxf-rt-wsdl-3.3.6.jar:3.3.6]
at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:127) ~[cxf-rt-wsdl-3.3.6.jar:3.3.6]
但是它成功通过了
的验证
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<Add xmlns="http://tempuri.org/">
<Add>
<intA>1</intA><intB>2</intB>
</Add>
</Add>
</soap:Body>
</soap:Envelope>
但在这种情况下,传递给 MyInvoker 的参数是一个包含两个空元素的数组。尽管如此,它还是生成了正确格式的(除了计算值是错误的,因为输入参数为空)响应
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns1:AddResponse xmlns:ns1="http://tempuri.org/">
<AddResult xmlns="http://tempuri.org/">0</AddResult>
</ns1:AddResponse>
</soap:Body>
</soap:Envelope>
所以问题是 - 解组以下有效请求会出现什么问题?
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<Add xmlns="http://tempuri.org/">
<intA>1</intA><intB>2</intB>
</Add>
</soap:Body>
</soap:Envelope>
我已经使用测试过的 WSDL 检查了 CXF 动态客户端调用,我从中借用了 JAXB 数据绑定,并且它在调用此服务时生成完全相同的请求,但由于某种原因似乎无法解组它.
另外一个问题,我觉得跟第一个有关,为什么第二个请求的时候unmarshalled参数是null?对接下来要看的地方有什么建议吗?
提前致谢
这是我自己问题的答案。如果通过添加一些服务器部分拦截器重用来自动态客户端的 CXF 服务实例,事情就会变得正确:
Service svc = client.getEndpoint().getService();
// Server part interceptors
svc.getInInterceptors().add(new ServiceInvokerInterceptor());
svc.getInInterceptors().add(new OutgoingChainInterceptor());
svc.getInInterceptors().add(new OneWayProcessorInterceptor());
我正在寻找将 CXF 作为 Web 服务实施提供者集成到应用程序中的解决方案。应用程序应该能够基于提供的 WSDL 文件以动态方式实现 Web 服务(这意味着 SEI 类 不可用)。由于应用程序通过自己的 servlet 管理 http 请求和 url 映射,因此使用标准 CXF servlet 发布端点是不可行的。另外,我想使用 JAXB 数据绑定。理想情况下,CXF 应该调用我的 Object invoke(String oper, Object... args)
来真正处理 Web 服务。总体而言,它应该看起来像动态客户端,但为服务器部分实现。
我已经设法使代码几乎可以正常工作,但遇到了一些我不明白的事情 - 稍后再说。
首先我将 WSDL 读入一个字符串并创建它的定义。定义预缓存在 wsdlManager 中,可以通过唯一引用访问。然后我创建 JaxWS 动态客户端并获取由 CXF 为其生成的 JAXB 数据绑定。
WSDLManager wsdlManager = serviceBus.getExtension(WSDLManager.class);
WSDLFactory wsdlFactory = wsdlManager.getWSDLFactory();
// Reader
WSDLReader reader = wsdlFactory.newWSDLReader();
reader.setFeature("javax.wsdl.verbose", true);
reader.setFeature("javax.wsdl.importDocuments", true);
Definition def = reader.readWSDL(null, TypeCast.getInputSource(wsdl)); // wsdl is a String containing wsdl definition
// Precache definition using listenerRef as unique identifier
wsdlManager.addDefinition(listenerRef, def);
String[] compileOptions = null;
// Create JAXWS dynamic client using precached address
Client client = createClient(listenerRef, simpleDataBinding, allowElementReferences, compileOptions);
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: service client is created succefully: " + listenerName);
EndpointInfo cei = client.getEndpoint().getEndpointInfo();
// Use JAXB generated databinding
DataBinding db = client.getEndpoint().getService().getDataBinding();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: databinding: " + db);
动态客户端的创建很简单
public Client createClient(String serviceDescription, boolean simpleDataBinding, boolean allowElementReferences, String[] schemaOptions) {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
ParentClassLoader dynaLoader = new ParentClassLoader();
JaxWsDynamicClientFactory dynamicClientFactory = JaxWsDynamicClientFactory.newInstance(serviceBus);
dynamicClientFactory.setSimpleBindingEnabled(simpleDataBinding);
dynamicClientFactory.setAllowElementReferences(allowElementReferences);
if (schemaOptions != null) {
dynamicClientFactory.setSchemaCompilerOptions(schemaOptions);
}
return dynamicClientFactory.createClient(serviceDescription, dynaLoader);
} catch (Throwable ex) {
Logger.error("WebServiceProcessor.createClient: exception is caught: " + ex, ex);
return null;
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
接下来,要创建服务器内容,需要声明一些助手 类
protected class MyWSDLServiceFactory extends WSDLServiceFactory {
public MyWSDLServiceFactory(Bus b, Definition d) {
super(b, d);
}
@Override
public Service create() {
Service svc = super.create();
// Post init
initializeDefaultInterceptors();
initializeDataBindings();
return svc;
}
}
public class MyInvoker extends AbstractInvoker {
protected final Object implementor = new Object();
public MyInvoker() {
}
@Override
public Object getServiceObject(Exchange context) {
return implementor;
}
protected void throwable() throws Exception {
}
@Override
public Object invoke(Exchange exchange, Object o) {
List<Object> params = null;
if (o instanceof List) {
params = CastUtils.cast((List<?>)o);
} else if (o != null) {
params = new MessageContentsList(o);
}
if (Logger.isTraceEnabled()) {
for (Object arg : params)
Logger.trace("MyInvoker.invoke: arg: " + arg);
}
// Method holding declararions of throwable exceptions
Method m = null;
try {
m = MsyInvoker.class.getMethod("throwable");
} catch (NoSuchMethodException ex) {
// Strange
}
return invoke(exchange, null, m, params);
}
@Override
protected Object performInvocation(Exchange exchange, Object serviceObject, Method m, Object[] paramArray) throws Exception {
Message inMessage = exchange.getInMessage();
BindingOperationInfo bop = exchange.getBindingOperationInfo();
String oper = bop.getName().getLocalPart();
// Process request
return processWebListenerRequest(oper, paramArray);
}
}
protected class MyDestinationFactory implements DestinationFactory {
protected final Set<String> prefixes = Collections.unmodifiableSet(new HashSet<String> (Arrays.asList("http://", "https://")));
@Override
public Destination getDestination(EndpointInfo ei, Bus bus) throws IOException {
return new MyDestination(ei, ei.getAddress());
}
@Override
public Set<String> getUriPrefixes() {
return prefixes;
}
@Override
public List<String> getTransportIds() {
return null;
}
}
protected class MyDestination extends ServletDestination {
public MyDestination(EndpointInfo ei, String path) throws IOException {
super(serviceBus, null, ei, path, false);
// Disable async support
isServlet3 = false;
}
@Override
protected void setupMessage(final Message inMessage, final ServletConfig config, final ServletContext context, final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
super.setupMessage(inMessage, config, context, req, resp);
}
@Override
protected String getBasePath(String contextPath) throws IOException {
if (endpointInfo.getAddress() == null) {
return "";
}
return endpointInfo.getAddress();
}
}
然后我们准备创建服务器:
MyWSDLServiceFactory sf = new MyWSDLServiceFactory(serviceBus, def);
sf.setAllowElementRefs(allowElementReferences);
sf.setDataBinding(db);
Service svc = sf.create();
// Clear cached definition
wsdlManager.removeDefinition(def);
svc.setInvoker(new MyInvoker());
// Create endpoints
for (ServiceInfo inf : svc.getServiceInfos()) {
for (EndpointInfo ei : inf.getEndpoints()) {
if (ei.getName().equals(cei.getName())) {
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: endpoint: " + ei.getName());
String addr = "/" + listenerRef;
try {
ei.setAddress(addr);
JaxWsEndpointImpl ep = new JaxWsEndpointImpl(serviceBus, svc, ei);
svc.getEndpoints().put(ei.getName(), ep);
ep.addHandlerInterceptors();
ep.getInInterceptors().add(new SoapUtil.SoapInLogger());
BindingFactoryManager bfm = serviceBus.getExtension(BindingFactoryManager.class);
// tried this but no effect
// ei.getBinding().setProperty("soap.force.doclit.bare", Boolean.TRUE);
String bindingId = ei.getBinding().getBindingId();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: binding id: " + bindingId);
BindingFactory bindingFactory = bfm.getBindingFactory(bindingId);
Server server = new ServerImpl(serviceBus, ep, new MyDestinationFactory(), bindingFactory);
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: starting server: " + ei.getName());
server.start();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.initServiceListener: server is started: " + server.isStarted());
// Set reference
listeners.put(listenerRef, server); // Our map to keep web server listeners
} catch (EndpointException e) {
throw new ServiceConstructionException(e);
}
}
}
}
服务器调用看起来像
String address = "/" + listenerRef;
Server server = listeners.get(listenerRef); // Find our server listener in a map
if (server != null) {
Endpoint ep = server.getEndpoint();
EndpointInfo ei = ep.getEndpointInfo();
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.invoke: endpoint: " + listenerName);
try {
AbstractHTTPDestination dest = (AbstractHTTPDestination) server.getDestination();
AsyncContext asyncCtx = requestContext.getAsyncContext();
HttpServletRequest req = (HttpServletRequest) asyncCtx.getRequest();
HttpServletResponse resp = (HttpServletResponse) asyncCtx.getResponse();
ServletContext sctx = req.getServletContext();
ServletConfig scfg = null;
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.invoke: destination resolved successfully: " + listenerName);
// Trigger CXF processing
dest.invoke(scfg, sctx, req, resp);
if (Logger.isDebugEnabled())
Logger.debug("WebServiceProcessor.invoke: endpoint processed successfully: " + listenerName);
} catch (Exception ex) {
Logger.error("WebServiceProcessor.invoke: exception is caught: " + ex, ex);
}
}
正如我已经提到的,该解决方案几乎可以工作,我尝试使用 CXF 3.3 和我作为示例的一个 WSDL 对其进行测试 http://www.dneonline.com/calculator.asmx?WSDL。我设法使用 SoapUI 调用该服务并获得响应。但现在是奇怪的部分。当我用标准请求调用网络服务时
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<Add xmlns="http://tempuri.org/">
<intA>1</intA><intB>2</intB>
</Add>
</soap:Body>
</soap:Envelope>
它因解组错误而失败
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"http://tempuri.org/", local:"intA"). Expected elements are <{http://tempuri.org/}Add>,<{http://tempuri.org/}AddResponse>,<{http://tempuri.org/}Divide>,<{http://tempuri.org/}DivideResponse>,<{http://tempuri.org/}Multiply>,<{http://tempuri.org/}MultiplyResponse>,<{http://tempuri.org/}Subtract>,<{http://tempuri.org/}SubtractResponse>
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:932) ~[cxf-rt-databinding-jaxb-3.3.6.jar:3.3.6]
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:738) ~[cxf-rt-databinding-jaxb-3.3.6.jar:3.3.6]
at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:170) ~[cxf-rt-databinding-jaxb-3.3.6.jar:3.3.6]
at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.getPara(DocLiteralInInterceptor.java:325) ~[cxf-rt-wsdl-3.3.6.jar:3.3.6]
at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:127) ~[cxf-rt-wsdl-3.3.6.jar:3.3.6]
但是它成功通过了
的验证<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<Add xmlns="http://tempuri.org/">
<Add>
<intA>1</intA><intB>2</intB>
</Add>
</Add>
</soap:Body>
</soap:Envelope>
但在这种情况下,传递给 MyInvoker 的参数是一个包含两个空元素的数组。尽管如此,它还是生成了正确格式的(除了计算值是错误的,因为输入参数为空)响应
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns1:AddResponse xmlns:ns1="http://tempuri.org/">
<AddResult xmlns="http://tempuri.org/">0</AddResult>
</ns1:AddResponse>
</soap:Body>
</soap:Envelope>
所以问题是 - 解组以下有效请求会出现什么问题?
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<Add xmlns="http://tempuri.org/">
<intA>1</intA><intB>2</intB>
</Add>
</soap:Body>
</soap:Envelope>
我已经使用测试过的 WSDL 检查了 CXF 动态客户端调用,我从中借用了 JAXB 数据绑定,并且它在调用此服务时生成完全相同的请求,但由于某种原因似乎无法解组它.
另外一个问题,我觉得跟第一个有关,为什么第二个请求的时候unmarshalled参数是null?对接下来要看的地方有什么建议吗?
提前致谢
这是我自己问题的答案。如果通过添加一些服务器部分拦截器重用来自动态客户端的 CXF 服务实例,事情就会变得正确:
Service svc = client.getEndpoint().getService();
// Server part interceptors
svc.getInInterceptors().add(new ServiceInvokerInterceptor());
svc.getInInterceptors().add(new OutgoingChainInterceptor());
svc.getInInterceptors().add(new OneWayProcessorInterceptor());