如何在SOAP Web服务方法中捕获任何异常? [英] How to catch any exceptions in a SOAP webservice method?

查看:86
本文介绍了如何在SOAP Web服务方法中捕获任何异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Spring SOAP @WebMethod c>和 CXF 。而且我想捕获所有异常(已检查和未检查)并将其转换为自定义 @WebFault

I'm offering a SOAP @WebMethod using Spring and CXF. And I would like to catch any exceptions (checked and unchecked) and transform them to a custom @WebFault.

我可以以某种方式为我的 @WebSerivce 类分配错误处理程序/拦截器,这样我就不必提供额外的 try-catch 是否为每种网络服务方法阻塞?

Can I somehow assign a erro-handler/interceptor to my @WebSerivce class so that I don't have to provide extra try-catch blocks for every webserivce method?

<jaxws:endpoint implementor="de.MyService" address="/MyService" />

@Component
@WebService
public class MyService {
    @WebMethod
    public void test() throws MyException {
        try {
            service.run();
        } catch (Exception e) {
            throw new MyException("test");
        }
    }
}


@WebFault
public class MyException extends Exception {
    public MyException(String message) {
        super(message);
    }
}

因此,使用某种拦截器,我的方法将看起来像这样:

So that with some kind of interceptor, my methods would look like this:

    @WebMethod
    public void test() {
        service.run();
    }

有可能吗?

推荐答案

好吧,第一个建议使用低技术含量方法:为所有处理 try / catch 调用方法。将此方法委派给抽象的 doInvoke 方法,并使其成为所有JAXWS实现的策略,使其仅调用 invoke

Well, first one could suggest a "low tech" approach : have a base class for all your webservices that handles the try/catch in a invoke method. Have this method delegate to an abstract doInvoke method, and make it a policy for all your JAXWS implementations to only call invoke.

@kan涉及AOP的解决方案也肯定是可能的解决方案。

@kan's solutions involving AOP also sure is a possible solution.

但是,如果要构建自定义错误拦截,则可以在CXF级别上进行。

However, if you want to build custom error interception, you can do so at the CXF level.

与JAX-WS一起使用时,CXF最简单形式可以被认为是JAX WS引擎周围的(复杂)拦截器链:拦截器链是CXF所有肉所处的位置。

When used with JAX-WS, CXF in its simplest form can be thought of as a (complex) interceptor chain around the JAX WS engine : the interceptor chain(s) are where all the "meat" of CXF goes.

CXF拦截器按链状排列(内链,故障链,出和故障外链)。

CXF Interceptors are arranged into chains (the "in" chain, "in fault" chain, "out" and "out fault" chains).

每个链都有不同的阶段,例如: RECEIVE,(PRE / USER / POST)_STREAM,READ,(PRE / USER / POST)协议,UNMARSHAL,(PRE / USER / POST)LOGICAL,PRE_INVOKE,INVOKE,POST_INVOKE 是传入链的默认阶段。

Each chain has various "phases", for example : RECEIVE, (PRE/USER/POST)_STREAM, READ, (PRE/USER/POST)PROTOCOL, UNMARSHAL, (PRE/USER/POST)LOGICAL, PRE_INVOKE, INVOKE, POST_INVOKE are the default phases of the incomming chains.

拦截器被执行按顺序(阶段与优先级相关联,拦截器实现声明它们属于哪个阶段。在一个阶段内,每个拦截器都可以选择在其他某个拦截器类之前或之后进行选择。

Interceptors are executed "in order" (the phases are associated with priorities, and interceptor implementations declare which phase they belong to. Inside a phase, each interceptor can opt in the be placed before or after a certain other interceptor class).

在您的情况下,最重要的是 INVOKE 阶段的> ServiceInvokerInterceptor 负责调用 @Webservice 。处理完输入链中的所有拦截器后,CXF会将响应对象处理到输出链以对输出进行序列化(或者,如果您有单向SOAP方法,则在此停止所有操作,这是特例)。

Of most importance in your case, the ServiceInvokerInterceptor, which belongs to the INVOKE phase, is responsible for calling the @Webservice. When all interceptors in the "in" chain are processed, CXF handles the response object to the "out" chain for serializing the output (or stops everything here if you have a one way SOAP method, which is a special case).

如果标准链中任何地方发生异常,CXF会做两件事:

If an exception occurs anywhere in the standard chain, CXF will do two things :


  1. 它将使用handleFault方法将链停在原处,并调用所有以相反顺序处理的拦截器

  2. 然后将控制权转发给故障拦截器链( ,出故障)。

因此,您可以添加自己的SOAP故障捕获全部错误处理的一种可能方法

Therefore, a possible way for you to add your own SOAP fault "catch all" error handling is to use an interceptor based in this lifecycle.

您创建一个Interceptor实现(AbstractSoapInterceptor对此很有用)
您将其绑定到INVOKE阶段,然后 ServiceInvokerInterceptor

You create an Interceptor implementation (AbstractSoapInterceptor is good for that) You bind it to the INVOKE phase, before the ServiceInvokerInterceptor

public class YourInterceptor extends AbstractSoapInterceptor {
    public YourInterceptor() {
        super(Phase.INVOKE);
        addBefore(Arrays.asList(ServiceInvokerInterceptor.class.getName()));
        // This means handleMessage will be called juste before your @WebMethod
        // If it fails, you will be the first to be noticed through #handleFault()
    }
}

当正常消息通过时,此拦截器不执行任何操作:

This interceptor is not to do anything when a "normal message passes" :

@Override
public void handleMessage(SoapMessage message) throws Fault {
    // Do nothing
}

但这是要处理的错误:

@Override
public void handleFault(SoapMessage message) {
    // Every exception will be wrapped into a Fault object by CXF
    Fault f = (Fault) message.getContent(Exception.class);
    // You should inspect its g.getCause() to maybe identify what went wrong
    // A CXF Fault also much ressembles a SOAPFault element
    f.setMessage("Your SOAP Fault message");
    // You can access the DOM detail of the fault
    Element detail = f.getOrCreateDetail();
    Element newDetailEntry = detail.getOwnerDocument().createElementNS("detailNs", "detailName");
    newDetailEntry.setTextContent("Content for your soap fault detail");
    detail.appendChild(newDetailEntry);
    // And so on. f.setFaultCode(qName);...
}

另一种实现是用自定义的 SoapFault 交换原始的 Fault ,这也是 Fault的子类,如果它对您更有意义。

An alternative implementation would be to swap the original Fault by a custom SoapFault, which is also a subclass of Fault, if it makes more sense to you.

诚然,这比启动您自己的异常更加困难,但它允许您构建精确,有意义的肥皂故障。但是请注意,优良作法是仅启动作为WSDL一部分存在的SOAP Fault,因此与客户端进行巧妙交互,不要在此处构建与WSDL不匹配的错误(在您的情况下, @Webfault 定义。)

This admitedly is more difficult that launching your own exception, but it allows you to build precise, meaningfull soap faults. Please note however that it is good practice to launch only SOAP Faults that exist as part of your WSDL, so to play "nicely" with clients, do not build here faults that do not match your WSDL (in your case, the @Webfault definition).

最后,您必须声明要将拦截器添加到链中。这样做有多种方法:在每个bean上:

You finally have to declare your interceptor to be added to the chains. There are multiple ways of doing so : on a per bean basis :

<bean id="myIt" class="com.yourInterceptor" />
<jaxws:endpoint implementor="de.MyService" address="/MyService">
    <jaxws:inInterceptors>
      <ref bean="myIt"/>
    </jaxws:inInterceptor>
</jaxws:endpoint>

或者在公交车一级。

<cxf:bus>
    <cxf:inInterceptors>
        <ref bean="myIt"/>
    </cxf:inInterceptors>
</cxf:bus>

这篇关于如何在SOAP Web服务方法中捕获任何异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆