CXF异常处理

本文探讨了CXF在服务端如何处理异常,包括服务实现类和拦截器中的异常处理。异常统一被包装为org.apache.cxf.interceptor.Fault,并在抛出后中断当前拦截器链,转而执行异常拦截器链。异常不会跨拦截器链传播,且在处理过程中,异常对象会被设置为消息内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   本文将讨论一下,在CXF服务端的异常处理,主要包括服务实现类抛出异常与拦截器中抛出异常,抛出异常后CXF的处理流程。其实在CXF中,异常无论是在服务实现类还是拦截器中抛出,其处理方式是一样的,当服务方法中的异常抛出后,CXF会将异常包装为org.apache.cxf.interceptor.Fault类型,而拦截器中只能抛出Fault类型异常,其间接继承于java.lang.RuntimeException,也就是属于运行时异常。根据CXF中Web服务请求处理流程知道,CXF对请求的处理流程是,先调用输入拦截器链,然后调用服务方法,再调用输出拦截器链,最后将结果返回给客户端。拦截器链的实现类为org.apache.cxf.phase.PhaseInterceptorChain,调用拦截器的方法为:doIntercept,下面是源码:

@SuppressWarnings("unchecked")
public synchronized boolean doIntercept(Message message) {
	updateIterator();

	Message oldMessage = CURRENT_MESSAGE.get();
	try {
		CURRENT_MESSAGE.set(message);
		if (oldMessage != null 
			&& !message.containsKey(PREVIOUS_MESSAGE)
			&& message != oldMessage
			&& message.getExchange() != oldMessage.getExchange()) {
			message.put(PREVIOUS_MESSAGE, new WeakReference<Message>(oldMessage));
		}
		while (state == State.EXECUTING && iterator.hasNext()) {
			try {
				Interceptor<Message> currentInterceptor = (Interceptor<Message>)iterator.next();
				if (isFineLogging) {
					LOG.fine("Invoking handleMessage on interceptor " + currentInterceptor);
				}

				currentInterceptor.handleMessage(message);
				if (state == State.SUSPENDED) {
					 // 如果拦截器链处于挂起状态,则抛出异常
					throw new SuspendedInvocationException();
				}
				
			} catch (SuspendedInvocationException ex) {
				// 只处理SuspendedInvocationException
				if (iterator.hasPrevious()) {
					iterator.previous();
				}
				pause();
				throw ex;
			} catch (RuntimeException ex) {
				//因为在拦截器链的执行过程抛出的异常都是Fault类型,所以异常由该处理器处理
				if (!faultOccurred) {//如果之前没有发生异常
					//标记为已发生异常
					faultOccurred = true;
										
					StringBuilder description = new StringBuilder();
					//拼凑日志内容
					
					//将异常对象作为消息内容
					message.setContent(Exception.class, ex);
					//调用该拦截器链中之前的拦截器处理异常
					unwind(message);
					
					//省略...
					
					//如果异常观察者不为空并且,Exchange不是单向的,调用异常观察者的onMessage方法
					//这与消息观察者的机制是一致的,只不过异常观察者针对的是FaultInterceptor
					//详情可参见http://blog.csdn.net/xtayfjpk/article/details/45116833
					if (faultObserver != null && !isOneWay) {
						faultObserver.onMessage(message);
					}
				}
				//标记状态为意外终止
				state = State.ABORTED;
			} 
		}
		if (state == State.EXECUTING) {
			state = State.COMPLETE;
		}
		return state == State.COMPLETE;
	} finally {
		CURRENT_MESSAGE.set(oldMessage);
	}
}


@SuppressWarnings("unchecked")
public void unwind(Message message) {
	while (iterator.hasPrevious()) {
		Interceptor<Message> currentInterceptor = (Interceptor<Message>)iterator.previous();
		if (isFineLogging) {
			LOG.fine("Invoking handleFault on interceptor " + currentInterceptor);
		}
		try {
			//依次调用已经迭代过的拦截器的handleFault方法
			//如果异常是在拦截器中抛出的,则会包含抛出异常的拦截器
			currentInterceptor.handleFault(message);
		} catch (RuntimeException e) {
			LOG.log(Level.WARNING, "Exception in handleFault on interceptor " + currentInterceptor, e);
			throw e;
		} catch (Exception e) {
			LOG.log(Level.WARNING, "Exception in handleFault on interceptor " + currentInterceptor, e);
			throw new RuntimeException(e);
		}
	}
}

从上面的源码分析,我们可以得到几个结论:
1. 无论是服务方法还是在拦截器中抛出的异常都被包装为了org.apache.cxf.interceptor.Fault类型
2. 异常一旦抛出,拦截器链立即终止执行,转入异常拦截器链执行
3. 输入拦截器链与输出拦截器链之间异常不会相互影响,也就是说如果输出拦截器链中抛出异常不会调用到输入拦截器链的异常处理方法
4. 在异常处理过程中,异常对象作为消息内容放置Message中,即:message.setContent(Exception.class, ex);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值