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

发布于 2024-09-15 14:12:07 字数 2383 浏览 3 评论 0原文

我有两个 Web 应用程序:一个 Web 服务客户端和一个服务器(均基于 CXF,使用 简单的前端方法)。

这是服务器定义:

<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 的接口(名称已更改...),客户端和服务器都知道该接口,上面的客户端定义创建了一个可以使用此注入的代理客户端界面。

当两个网络应用程序都运行时,一切都运行得很好,特别是当我先部署服务器,然后部署客户端时。但是,当服务器 webapps 无法正确启动时,客户端 webapp 将陷入无限循环,尝试从不存在的 WSDL 创建代理。

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

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

I have two webapps: a web-service client and a server (both CXF-based, using the Simple Front-End approach).

This is the server definition:

<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>

And here the client:

<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>

I have an interface called ThingyService (the names have been changed ...) that is known to both client and server and the above client definition creates a proxy client that can be injected using this interface.

Everything works beautifully when both webapps are running, specifically when I deploy the server first and then the client. But when the server webapps does not start correctly, the client webapp hangs in an infinite loop trying to create the proxy from the non-existent WSDL.

Basically what I'd like is a proxy around the service proxy that lets the calls pass through when the service is available and throws an adequate exception when the service is down, which I can catch and show a "sorry, we're offline" page in the gui and resumes service when the web service is available again. I have access to the WSDL in static form through the build process (generated automatically through cxf maven plugins), so I could use this for the initial configuration, so from that point of view I am independent of the server.

Does anybody have any pointers in how to implement this functionality? The server is tomcat. The webapps may or may not be deployed onto the same server during production. The backend uses spring / jpa / cxf, the front end uses spring / wicket.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

貪欢 2024-09-22 14:12:07

听起来您想要离线创建 Web 服务代理/客户端代码,而不是在运行时生成代理。

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

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

Instead of generating a proxy at runtime, it sounds like you want to create the web service proxy / client code offline.

I'm not sure how this is handled with CXF but you can use tools like wsdl2java to generate the web service client code for a given wsdl document.

As an alternative approach, the client bean could be pointed at a static wsdl file, rather than one located on a remote server.

街道布景 2024-09-22 14:12:07

尽管静态 wsdl 创建方法很有前途,但我选择了一种不同的方法(主要是因为 cxf maven 代码生成有错误)。

我在现有的工厂Bean周围包装了另一个factoryBean,并将其附加到一个服务提供者对象,该对象定期 ping wsdl URL 以获得可用性。我将服务代理保存在工厂 bean 内的缓存中,一旦创建,就会在服务提供者 ping 失败时立即将其删除。

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

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

这是我的 spring 配置的摘录:

<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" />

Although the static wsdl creation approach was promising, I chose a different one (mainly because the cxf maven code generation is buggy).

I wrapped another factoryBean around the existing one, and I attached it to a service provider object that regularly pings the wsdl URL for availability. I keep a service proxy in a cache inside the factory bean, once it is created, and delete it as soon as the service provider ping fails.

If the service is currently not available, my FactoryBean throws a ServiceNotAvailableException. My front end catches this and shows a nice "Service currently unavailable" page.

Additionally, an AspectJ aspect catches all writing calls to the service and re-schedules them when the service is available again.

Here is an excerpt from my spring config:

<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" />
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文