Apache CXF
Posted onApache CXF
CXF是基于JAX-WS实现的,JAX-WS规范是一组XML web services的JAVA API,它使用户无需编写复杂的SOAP ENV,WSDL。在 JAX-WS中,一个远程调用可以转换为一个基于XML的协议例如SOAP。在使用JAX-WS过程中,开发者不需要编写任何生成和处理SOAP消息的代码。JAX-WS的运行时实现会将这些API的调用转换成为对于SOAP消息。
在服务器端,用户只需要通过Java语言定义远程调用所需要实现的接口SEI (service endpoint interface),并提供相关的实现,通过调用JAX-WS的服务发布接口就可以将其发布为WebService接口。 在客户端,用户可以通过JAX-WS的API创建一个代理(用本地对象来替代远程的服务)来实现对于远程服务器端的调用。 来源: [http://blog.csdn.net/chjttony/article/details/6196289](http://blog.csdn.net/chjttony/article/details/6196289)
一、与Axis2的不同之处 1、Apache CXF 支持 WS-Addressing、WS-Policy、WS-RM、WS-Security和WS-I BasicProfile 2、Axis2 支持 WS-Addressing、WS-RM、WS-Security和WS-I BasicProfile,WS-Policy将在新版本里得到支持 3、Apache CXF 是根据Spring哲学来进行编写的,即可以无缝地与Spring进行整合 4、Axis2 不是 5、Axis2 支持更多的 data bindings,包括 XMLBeans、JiBX、JaxMe 和 JaxBRI,以及它原生的 data binding(ADB)。 6、Apache CXF 目前仅支持 JAXB 和 Aegis,并且默认是 JAXB 2.0,与 XFire 默认是支持 Aegis 不同,XMLBeans、JiBX 和 Castor 将在 CXF 2.1 版本中得到支持,目前版本是 2.0.2 7、Axis2 支持多种语言,它有 C/C++ 版本。 8、Apache CXF 提供方便的Spring整合方法,可以通过注解、Spring标签式配置来暴露Web Services和消费Web Services
二、A simple JAX-WS service 原文见http://cwiki.apache.org/CXF20DOC/a-simple-jax-ws-service.html
来源: http://www.iteye.com/topic/143877 CXF旨在为服务创建必要的基础设施,它的整体架构主要由以下几个部分组成:
1.Bus
它是C X F架构的主干,为共享资源提供了一个可配置的场所,作用非常类似于S p r i n g的ApplicationContext。这些共享资源包括WSDL管理器、绑定工厂等。通过对Bus进行扩展,可以方便地容纳自己的资源,或替换现有的资源。默认Bus实现是基于Spring的,通过依赖注入,将运行时组件串起来。Bus的创建由BusFactory负责,默认是 SpringBusFactory,对应于默认Bus实现。在构造过程中,SpringBusFactory会搜索META-INF/cxf(就包含在 CXF的Jar中)下的所有Bean配置文件,根据它们构建一个ApplicationContext。开发者也可提供自己的配置文件来定制Bus。
2.消息传递和拦截器(Interceptor)
CXF建立于一个通用的消息层之上,主要由消息、拦截器和拦截器链(InterceptorChain)组成。CXF是以消息处理为中心的,熟悉 JSP/Servlet的开发者可以将拦截器视为CXF架构中的“Filter”,拦截器链也与“FilterChain”类似。通过拦截器,开发者可以方便地在消息传递、处理的整个过程中对CXF进行扩展。拦截器的方法主要有两个:handleMessage和handleFault,分别对应消息处理和错误处理。在开发拦截器的时候需要注意两点:
拦截器不是线程安全的,不建议在拦截器中定义实例变量并使用它。这一点跟JSP/Servlet中对于Filter的处理是一样的;
不要调用下一个拦截器的handleMessage或handleFault,这个工作由InterceptorChain来完成。
3.前端(Front End)
它为CXF提供了创建服务的编程模型,当前主要的前端就是JAX-WS。
4.服务模型
CXF中的服务通过服务模型来表示。它主要有两部分:ServiceInfo和服务本身。ServiceInfo作用类似WSDL,包含接口信息、绑定、端点(EndPoint)等信息;服务则包含了ServiceInfo、数据绑定、拦截器和服务属性等信息。可使用Java类和WSDL来创建服务。一般是由前端负责服务的创建,它通过ServiceFactory来完成。
5.绑定(Binding)
绑定提供了在传输之上映射具体格式和协议的方法,主要的两个类是Binding和BindingFactory。BindingFactory负责创建Binding。
6.传输(Transport)
为了向绑定和前端屏蔽传输细节,CXF提供了自己的传输抽象。其中主要有两个对象:Conduit和Destination。前者是消息发送的基础,后者则对应消息接收。开发者还可以给Conduit和Destination注册MessageObserver,以便在消息发送和接收时获得通知。
开发方法
CXF 可以创建的Web 服务应用有两种:服务提供者和服务消费者。这种结构可类比客户端/ 服务器结构,服务消费者类似于客户端,服务提供者类似于服务器。使用CXF 创建应用时,服务提供者和服务消费者并不需要同时出现,因为有可能应用只是作为服务提供者或服务消费者单独出现。 来源: [http://blog.csdn.net/jacklee_6297/article/details/5888232](http://blog.csdn.net/jacklee_6297/article/details/5888232) 开发Webservice工程步骤:
2.使用CXF开发Webservice工程步骤:
1).为CXF设置编译和开发环境 在http://cxf.apache.org/download.html 下载相应的CXF包,/lib目录下的jar 文件引入工程 2).创建基于XCF的Webservice服务端工程。 3).编写Webservice的客户端程序,调用服务端服务。
3.CXF中的Factory:
CXF不但可以使用JAX-WS开发web服务,也可以将POJO发布为web服务,对于这两种不同的方式,对应的factory如下:
服务端 客户端
JAX-WS JaxWsServerFactoryBean JaxWsProxyFactoryBean
POJO ServiceFactoryBean ClientProxyFactoryBean
4.CXF使用JAX-WS开发服务端:
(1).定义服务接口:
在接口上添加Webservice注解:@WebService。如:
[java] view plaincopy
- package service;
- import javax.jws.WebService;
- @WebService
- public interface OrderProcess {
- String processOrder(Order order);
- }
(2).实现服务接口:
在实现类上也添加Webservice注解:@WebService(endpointInterface = 服务接口全路径, serviceName = 对外发布的服务名)。如:
[java] view plaincopy
- package service;
- import javax.jws.WebService;
- @WebService(endpointInterface = "service.OrderProcess",serviceName=”order”)
- public class OrderProcessImpl implements OrderProcess {
- public String processOrder(Order order) {
- return "hello world"+order;
- }
- }
(3).对外发布服务:
[java] view plaincopy
- //创建web服务工厂
- JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
- //设置服务类
- factory.setServiceClass(服务接口实现类.class);
- //设置对外发布服务地址
- factory.setAddress(对外发布的服务地址);
- //创建服务
- Server server = factory.create();
- //启动服务
- server.start();
5.CXF使用JAX-WS开发客户端:
[java] view plaincopy
- //创建web服务代理工厂
- JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
- //设置要调用的web服务服务端发布地址
- factory.setAddress(web服务的发布地址);
- //设置要调用的web服务
- factory.setServiceClass(web服务接口.class);
- //创建web服务对象
- 服务接口 对象 = (服务接口) factory.create();
- 通过对象调用web服务的方法
- 6.CXF使用POJO开发服务端:
- 和使用JAX-WS开发方式前两步完全一样,第三步稍有不同如下:
- //创建web服务工厂
- ServiceFactoryBean svrFactory = new ServiceFactoryBean();
- //设置服务类
- svrFactory.setServiceClass(服务接口实现类.class);
- //设置对外发布服务地址
- svrFactory.setAddress(对外发布的服务地址);
- //创建服务
- Server server = svrFactory.create();
- //启动服务
- server.start();
6.CXF使用POJO开发客户端:
和JAX-WS方式除了代理工厂不同以外,其他均相同:
[java] view plaincopy
- //创建web服务代理工厂
- ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
- //设置要调用的web服务服务端发布地址
- factory.setAddress(web服务的发布地址);
- //设置要调用的web服务
- factory.setServiceClass(web服务接口.class);
- //创建web服务对象
- 服务接口 对象 = (服务接口) factory.create();
通过对象调用web服务的方法
7.CXF与Spring的集成:
(1).对工程引入spring支持。
(2).在web.xml文件中添加spring和CXF相应的配置如下:
[xhtml] view plaincopy
contextConfigLocation spring配置文件路径 - org.springframework.web.context.ContextLoaderListener
CXFServlet CXF Servlet - org.apache.cxf.transport.servlet.CXFServlet
1 CXFServlet /service//*
(3).在spring配置文件中导入CXF的相关配置如下:
[xhtml] view plaincopy
(4).在spring配置文件中配置要发布的web服务如下:
[xhtml] view plaincopy
- <jaxws:endpoint
- id="……"
- implementor="服务接口实现类全路径"
address="/web服务发布地址(相对地址)" />
拦截器方式的使用实例:
基于CXF2.0前2个学习笔记,对原先服务端与客户端进行修改,实现在SOAP Header里面添加自定义的数据进行认证 在做之前,先要理解如下的信息 拦截器(Interceptor)简单说明 Interceptor是CXF架构中一个很有特色的模式。你可以在不对核心模块进行修改的情况下,动态添加很多功能。这对于CXF这个以处理消息为中心的服务框架来说是非常有用的,CXF通过在Interceptor中对消息进行特殊处理,实现了很多重要功能模块,例如:日志记录,Soap消息处理,消息的压缩处。简单的说,可以在收到请求后,还未进行业务处理前,进行处理。或者在请求包发送前,进行报文的处理。 几个的API的介绍 Interceptor
定义两个方法,一个处理消息 handleMessage, 一个是处理错误 handleFault。
InterceptorChain 单个的Interceptor功能有限,CXF要实现一个SOAP消息处理,需要将许许多多的Interceptor组合在一起使用。因此设计了 InterceptorChain,在我看了InterceptorChain就像是一个Interceptor的小队长。 小队长有调配安置Interceptor的权力(add,remove),也有控制消息处理的权力(doInterceptor,pause,resume,reset,abort),同时也有交付错误处理的权力( {get|set}FaultObserver)。更有意思的是为灵活控制Interceptor的处理消息顺序(doInterceptStartingAt,doInterceptorStartingAfter),这也是InterceptorChain比较难理解的地方。 Fault 定义了CXF中的错误消息。 InterceptorProvider 这里定义了Interceptor的后备保障部队。我们可以在InterceptorProvider中设置In,Out,InFault,OutFault 后备小分队,添加我们所希望添加的Interceptor。而InterceptorChain会根据这些后备小分队,组建自己的小分队实例,完成具体的作战功能任务。 AbstractAttributedInterceptorProvider InterceptorProvider实现的抽象类,由于这个类来继承了HashMap,我们可以像这个类中存储一些属性信息。 AbstractBasicInterceptorProvider 与AbstractAttributedInterceptorProvider不同,这个Interceptor只是简单实现了InterceptorProvider的功能,并不提供对其属性存储的扩展。 Message 由于Interceptor是针对Message来进行处理的,当你打开Message这个类文件时,你会发现在Message中定义了很多常量,同时你还可以从Message中获取到很多与Message操作相关的信息。可以获取设置的对象有InterceptorChain Exchange Destination,还有获取设置Content的泛型接口,是不是感觉Message和Bus差不多,都成了大杂货铺,一切与消息处理相关的信息都可以放在Message中。
理解了Interceptor功能,下面的修改就很简单了
服务端修改
1.新建一个拦截器(Interceptor)
package hs.cxf.soapHeader;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.NodeList;
///
/
/ @Title:获取soap头信息
/
/ @Description:
/
/ @Copyright:
/
/ @author zz
/ @version 1.00.000
/
//
public class ReadSoapHeader extends AbstractPhaseInterceptor
服务端的配置就告一段落了,接下来是客户端的修改
客户端
1.同样新增一个Interceptor
package hs.cxf.client.SoapHeader;
import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
//
public AddSoapHeader(){
super(Phase.WRITE);
}
public void handleMessage(SoapMessage message) throws Fault {
String spPassword="wdwsb";
String spName="wdw";
QName qname=new QName("RequestSOAPHeader");
Document doc=DOMUtils.createDocument();
//自定义节点
Element spId=doc.createElement("tns:spId");
spId.setTextContent(spName);
//自定义节点
Element spPass=doc.createElement("tns:spPassword");
spPass.setTextContent(spPassword);
Element root=doc.createElementNS(nameURI, "tns:RequestSOAPHeader");
root.appendChild(spId);
root.appendChild(spPass);
SoapHeader head=new SoapHeader(qname,root);
List
headers.add(head);
System.out.println(">>>>>添加header<<<<<<<");
}
}
2.客户端调用程序修改
package hs.cxf.client;
import hs.cxf.client.SoapHeader.AddSoapHeader;
import java.util.ArrayList;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
///
/ @Title:
/
/ @Description:
/
/ @Copyright:
/
/ @author zz
/ @version 1.00.000
/
//
public class TestClient {
///
/ 测试1
//
@SuppressWarnings("unchecked")
public void testSend1() {
try {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
ArrayList
// 通过对象来交互
ReqBean req = new ReqBean();
req.setExp(new JAXBElement
posted on 2011-04-19 14:23 fatbear 阅读(3424) 评论(10) 编辑 收藏 所属分类: web service
[
评论
]()
/# re: CXF2.0学习笔记-3 SOAP Header 2011-04-21 19:01 akana
hello,我想问一下你的ReadSoapHeader这个服务端读取soap header实现成功了吗?我这里用这种方式总是出错: head = mess.getSOAPHeader();出现java.lang.NullPointerException错误。。 回复 更多评论
/# re: CXF2.0学习笔记-3 SOAP Header 2011-04-21 19:02 akana
另外问一下你学习CXF2.0的资料有哪些呢?可以推荐一下吗? 回复 更多评论
/# re: CXF2.0学习笔记-3 SOAP Header 2011-04-22 11:55 akana
@akana 找到错误了。我的ReadSoapHeader引用了 import org.apache.xmlbeans.impl.soap.SOAPException; import org.apache.xmlbeans.impl.soap.SOAPHeader; import org.apache.xmlbeans.impl.soap.SOAPMessage; 而应该是 import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; 回复 更多评论
/# re: CXF2.0学习笔记-3 SOAP Header 2011-04-22 21:53 fatbear
@akana 呵呵,我也是看官方文档与网络上的资料后,自己写的,一般都有经过测试的 回复 更多评论
/# re: CXF 2.0 学习笔记-3 SOAP Header 2011-08-31 11:08 无
您好,ReadSoapHeader这个服务端读取soap header时,mess这个一直都是空的,这是怎么回事呀? 回复 更多评论
/# re: CXF 2.0 学习笔记-3 SOAP Header 2012-07-12 15:27 林子
factory.setOutInterceptors(list); factory.setServiceClass(WebServiceSample.class); factory.setAddress("http://127.0.0.1:8080/cxfTest/ws/HelloWorld"); 类org.apache.cxf.jaxws.JaxWsProxyFactoryBean 没有以上3个方法,引用的路径完全一样。。 回复 更多评论
/# re: CXF 2.0 学习笔记-3 SOAP Header 2012-07-12 16:45 林子
@林子 我找到原因了,那是因为这3个方法时父类的方法而我没导入他父类的jar包,但是又抛了一个新异常: Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Could not find conduit initiator for transport http://schemas.xmlsoap.org/soap/http at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:146) at $Proxy25.sendSms(Unknown Source) at Test.main(Test.java:48) Caused by: java.lang.RuntimeException: Could not find conduit initiator for transport http://schemas.xmlsoap.org/soap/http at org.apache.cxf.binding.soap.SoapTransportFactory.getConduit(SoapTransportFactory.java:230) at org.apache.cxf.endpoint.AbstractConduitSelector.getSelectedConduit(AbstractConduitSelector.java:81) at org.apache.cxf.endpoint.UpfrontConduitSelector.prepare(UpfrontConduitSelector.java:61) at org.apache.cxf.endpoint.ClientImpl.prepareConduitSelector(ClientImpl.java:809) at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:505) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:440) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:343) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:295) at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73) at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124) ... 2 more 回复 更多评论
/# re: CXF 2.0 学习笔记-3 SOAP Header 2012-07-26 08:45 fatbear
@林子 现在开发cxf已经很简单了,eclipse3.7已经自带有cxf插件,可以很方便的生成服务端与客户端,你可以用那个来弄,基本就不会有问题了 回复 更多评论
/# re: CXF 2.0 学习笔记-3 SOAP Header[未登录] 2012-12-18 14:40 randy
能解释下这两句代码的意思吗? if (mess == null) { saa.handleMessage(message); mess = message.getContent(SOAPMessage.class); } 还有什么情况下mess会为null?谢谢 回复 更多评论
/# re: CXF 2.0 学习笔记-3 SOAP Header[未登录] 2013-06-06 12:08 Eason
xml格式:
来源: [http://www.blogjava.net/fatbear/archive/2011/04/19/348567.html](http://www.blogjava.net/fatbear/archive/2011/04/19/348567.html)