Spring,CXF:Web服务客户端和服务器之间的松散耦合

时间:2010-08-23 13:55:07

标签: java web-services spring soap cxf

我有两个webapps:一个Web服务客户端和一个服务器(基于CXF,使用Simple Front-End方法)。

这是服务器定义:

<simple:server id="server" bindingId="http://schemas.xmlsoap.org/soap/"
    address="/thingy" transportId="http://schemas.xmlsoap.org/soap/"
    serviceName="cs:thingyService"
    serviceClass="com.mycompany.thingy.api.service.ThingyService"
    endpointName="cs:thingyServicePort">
        <simple:serviceBean>
            <bean class="com.mycompany.thingy.server.service.ThingyServiceDelegate">
                <property name="thingyService" ref="thingyService"></property>
            </bean>
        </simple:serviceBean>

        <simple:dataBinding>
            <bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" />
        </simple:dataBinding>
        <simple:binding>
            <soap:soapBinding version="1.1" mtomEnabled="true" />
        </simple:binding>
</simple:server>

在这里客户:

<http-conf:conduit name="*.http-conduit">
    <http-conf:client AllowChunking="false" />
</http-conf:conduit>

<simple:client id="thingyService" wsdlLocation="${wsdl.url}?wsdl"
    serviceName="cs:thingyService"
    endpointName="cs:thingyServicePort"
    transportId="http://schemas.xmlsoap.org/soap/"
    address="${wsdl.url}"
    bindingId="http://schemas.xmlsoap.org/soap/"
    serviceClass="com.mycompany.thingy.api.service.ThingyService">
        <simple:dataBinding>
            <bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" />
        </simple:dataBinding>
        <simple:binding>
            <soap:soapBinding mtomEnabled="true" version="1.1" />
        </simple:binding>
</simple:client>

我有一个名为ThingyService的接口(名称已被更改...),客户端和服务器都知道,上面的客户端定义创建了一个可以使用此接口注入的代理客户端。

当两个webapp都在运行时,一切都运行得很好,特别是当我首先部署服务器然后再部署客户端时。但是当服务器webapps无法正常启动时,客户端webapp会在无限循环中挂起,尝试从不存在的WSDL创建代理。

基本上我想要的是服务代理周围的代理,当服务可用时让调用通过,并在服务停止时抛出足够的异常,我可以捕获并显示“抱歉,我们”重新离线“gui中的页面,并在Web服务再次可用时恢复服务。我可以通过构建过程(通过cxf maven插件自动生成)以静态形式访问WSDL,因此我可以将其用于初始配置,因此从这个角度来看,我独立于服务器。

有人对如何实现此功能有任何指示吗?服务器是tomcat。在生产期间,webapps可能会也可能不会部署到同一服务器上。后端使用spring / jpa / cxf,前端使用spring / wicket。

2 个答案:

答案 0 :(得分:2)

您可能希望脱机创建Web服务代理/客户端代码,而不是在运行时生成代理。

我不确定如何使用CXF处理这个问题,但您可以使用wsdl2java等工具为给定的wsdl文档生成Web服务客户端代码。

作为替代方法,客户端bean可以指向静态wsdl文件,而不是位于远程服务器上的文件。

答案 1 :(得分:1)

虽然静态wsdl创建方法很有前景,但我选择了另一种方法(主要是因为cxf maven代码生成有问题)。

我在现有的一个上包装了另一个factoryBean,并将它附加到定期pings the wsdl URL for availability的服务提供者对象。我将服务代理保存在工厂bean的一个缓存中,一旦创建它,​​并在服务提供者ping失败后立即将其删除。

如果该服务当前不可用,我的FactoryBean会抛出ServiceNotAvailableException。我的前端捕获了这个并显示了一个很好的“服务当前不可用”页面。

此外,AspectJ方面捕获对服务的所有写入调用,并在服务再次可用时重新调度它们。

以下是我的春季配置的摘录:

<bean id="outerFactoryBean">
    <property name="innerFactory">
        <bean class="org.apache.cxf.frontend.ClientProxyFactoryBean">
             <!-- translation of spring:client definition from question -->
        </bean>
    </property>
    <property name="serviceProvider" ref="serviceProvider" />
</bean>
<bean id="serviceProvider" class="de.mytoys.shop.coupons.web.client.ServiceProvider">
    <property name="wsdlUrl" value="${wsdl.url}?wsdl" />
    <property name="connectionFactory">
        <bean class="org.apache.cxf.transport.http.HttpURLConnectionFactoryImpl" />
    </property>
</bean>

<task:scheduled-tasks>
    <task:scheduled ref="serviceProvider" method="checkAvailability"
        fixed-delay="1000" />
</task:scheduled-tasks>

<task:scheduler id="scheduler" pool-size="1" />