当前位置: 首页 > 工具软件 > Apache JaxMe > 使用案例 >

Apache CXF快速上手教程 (转)

蓬宾白
2023-12-01

基础架构

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 创建应用时,服务提供者和服务消费者并不需要同时出现,因为有可能应用只是作为服务提供者或服务消费者单独出现。

为了说明使用CXF 如何创建这两种类型的应用,本教程将同时给出它们的例子。另外,由于Groovy在Java 世界中变得越来越流行,本教程会给出使用Groovy 的CXF 插件GroovyWS 的实现例子。例子使用JDK 1.5.X 和Groovy 1.0 完成,包含以下几部分:

1.User,用户对象,在消费者和提供者之间传递;

2.UserService,用户管理服务,它提供增加和获取所有用户的功能;

3.Client,服务消费者,它向UserService发起服务请求。

Java 实现的步骤包括以下几点。

服务端包含UserService、UserServiceImpl和User。其中,UserService是接口定义,UserServiceImpl是它的实现,并负责服务的发布,服务只有发布之后才能被消费。例子使用了JAX-WS,它们的主要内容如下:


UserService

package server;
import javax.jws.WebService;
@WebService
public interface UserService {
void add(User user);
User[] findAllUsers();
}

@WebService 指明接口是Web 服务
UserServiceImpl

import java.util.List;
import java.util.Vector;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
@WebService(endpointInterface = "server.UserService",
serviceName = "UserService",
portName="UserServicePort")
public class UserServiceImpl implements UserService {
   static List<User> UserRepository= new Vector<User>();
   public void add(User user) {
      UserRepository.add(user);
   }
   public User[] findAllUsers() {
      User[] users= new User[UserRepository.size()];
      UserRepository.toArray(users);
      return users;
   }
   public static void main(String[] args){
      UserServiceImpl userService= new UserServiceImpl();
      Endpoint.publish("http://localhost:9000/userService", userService);
   }
}

@ WebService中的serviceName、portName,分别指定了其产生的WSDL中的服务名和端口名。endpointInterface为接口的类名。服务发布代码也可以放在另一个类中

User

package server;
public class User {
   String first;
   String last;
   public String getFirst() {
      return first;
   }
   public void setFirst(String first) {
      this.first = first;
   }
   public String getLast() {
      return last;
   }
   public void setLast(String last) {
      this.last = last;
   }
}

 2.客户端只有一个类:Client,其他的User、UserService引用server包中的对象。

package client;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import server.User;
import server.UserService;
public class Client {
public static void main(String[] arg){
Service service = Service.create(
new QName("http://server/", "UserService"));
service.addPort(new QName("http://server/", "UserServicePort")
, SOAPBinding.SOAP11HTTP_BINDING
, "http://localhost:9000/userService");
UserService userService= service.getPort(UserService.class);
User user= new User();
user.setFirst("James");
user.setLast("Bond");
userService.add(user);
User[] users= userService.findAllUsers();
for(User u : users){
System.out.println(u.getFirst()+"."+u.getLast());
}
}
}

 

注意,QName 的第一个参数指明了WSDL 的目标名字空间,可以通过“服务地址?wsdl”方式获取服务的WSDL,来查看服务的目标名字空间。对于由CXF 创建的服务,目标名字空间的默认构造规则是:http:// 包名的倒序/。即如果包名是a.b.c,那么名字空间就为http://c.b.a/ 。GroovyWS 的实现步骤包括以下几点。

1.服务端包括:User、UserService、User.aegis.xml。由于Groovy类包含一个metaClass属性,该属性不应该被序列化在服务端和客户端之间传递,User.aegis.xml用来指定将该属性忽略掉。

 

User

package server;
class User {
   String first
   String last
}

 UserService

package server;
import groovyx.net.ws.WSServer
class UserService {
private static List users= new Vector()
void add(User user){
users.add(user)
}
User[] findAllUsers(){
User[] u= new User[users.size()]
users.toArray(u)
return u
}
static void main(args) {
def server = new WSServer()
server.setNode("server.UserService",
"http://localhost:9000/UserService")
}
}

 

注意它的发布。

Use.aegis.xml

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns:sample="http://DefaultNamespace">
<mapping name="sample:User">
<property name="metaClass" ignore="true"/>
</mapping>
</mappings>

 2.客户端包含:Client和User.aegis.xml,User.aegis.xml的内容和服务端的一样。Client的内容如下:

package client;
import groovyx.net.ws.WSClient
class Client {
   static void main(args) {
      def proxy = new WSClient(
      "http://localhost:9000/UserService?wsdl", Client.class.classLoader)
      def user= proxy.create("defaultnamespace.User");
      user.first="James"
      user.last="Bond"
      proxy.add(user)
      def result= proxy.findAllUsers()
      result.users.each{
      println it.first+"."+it.last
      }
   }
}
 

相关建议

CXF 的功能特性非常多,要熟练使用它非得花些功夫才行。笔者在此给出一些建议,期望能对读
者在今后学习和使用CXF 的过程中有所帮助:

1.熟悉工具涉及领域的协议是个不错的主意。虽然CXF提供了简化服务创建的编程模型,但是如果不了解WS-*协议,在遇到问题调试时必然 会花不少时间。尤其是在SOA的环境中,客户端和服务不一定是使用同一语言、同一工具实现的情况下,互操作问题经常是由于对协议的不同支持造成的;

2.作为CXF实现内容的一个重点,JAX-WS是值得关注的;

3.在Java的环境中,Spring几乎已经成为开发服务器端应用的首选,应重点关注CXF和Spring的配合使用;

4.近些年来,Java世界的动态语言旋风愈演愈烈。Groovy由于其语法和Java兼容且提供了不少方便的语法,吸引了不少Java开 发者。更何况新兴的Grails框架逐渐引人注目,其前途不可限量。GroovyWS专为Groovy开发,且底层就是CXF,作为CXF的开发者,没有 理由不去使用可以使自己生活过得舒适的工具;

5.CXF携带了大量的例程,它们是熟悉和了解CXF的大门的;

6.参与社区,参与讨论,往往比起自己单干要有用得多。

版本信息

在官方网站上,CXF 公布了其2.0.4 版和2.1版的开发计划。2.0.4 版于2008 年1 月15 日发布,2.1 版则是2 月28 日发布。2.0.4 版的计划主要是修正2.0.3 版的错误,以及工具迁移的问题。2.1 版则引入一些新特性,包括:

1.支持JAX-WS 2.1,包括JAXB 2.1、API中的WS-A、SEI接口方法的JAXB标注、WebServiceFeature标注;

2.XmlBeans、JiBX数据绑定;

3.新的java2ws工具;

4.更好地支持REST(JSR-311);

5.支持js;

6.OSGi bundling。

除了上述计划,有可能包含在2.1 版,但是肯定会在2.2 版的特性包括:

1.通过继承Yoko 的代码来支持CORBA;

2.更好地集成Acegi;

3.WS-SecureConversation/Trust;

4.其他WS-*协议。

社区视角

在Celtix 和XFire 宣布合并的同年,另一个著名开源Web 服务框架Axis 的后继者Axis2 也诞生了。Axis2 并非Axis 的2.0 版,而是完全重写了Axis 的新项目。作为功能和背景都极其相似的两个项目,人们难免会将它们相提并论。在著名的Java 企业开发站点TheServiceSide 上就有一篇名为“Axis, Axis2 and CXF: Survey theWS Landscape”(地址:http://www.theserverside.com/tt/articles/content/AxisAxis2andCXF/article.html )的文章对这两个项目进行了比较,主要内容如下。

1.在特性方面:

C X F 支持W S - A d d r e s s i n g 、W S -Policy、WS-RM、WS-Security和WS-I BasicProfile。Axis2支持除了WSPolicy之外的所有这些标准,WS-Policy预计会在未来版本中得到支持;

CXF可以方便地和Spring集成在一起,Axis2不行;

Axis2支持范围更广的数据绑定,包括XMLBeans、JiBX、JaxMe、JaxBRI,以及它自己的数据绑定ADB。在 Axis21.2 版中,JaxME和JaxBRI尚处于试验阶段。目前,C X F只支持J A X B和Aegis,对XMLBeans、JiBX和Castor的支持将在CXF 2.1版中实现;

Axis2支持多语言,除了Java版本,尚有C/C++版本。

2.在开发方面:

Axis2更像一个微型服务器。Axis2被打包成一个WAR,可部署到任何Servlet容器中,为了更方便地在运行中管理和部署服务进行专门的设计。

CXF更专注于对开发人员友好及可嵌入性。大部分配置只需使用API即可完成,与Spring紧密集成。CXF强调代码优先的服务开发方式。

3.建议:如果需要多语言支持,那么就采用Axis2;如果考虑到使用Java、与Spring集成,或将服务嵌入到其他程序中,那么CXF更好。

当然,并不是所有人都说好。例如,在国内的一些论坛上,就有开发者抱怨CXF 的入门比起XFire 来要复杂得多。这是可以理解的,毕竟CXF本身也比XFire 要复杂得多。为了帮助Celtix 和XFire 的开发者向新工具的迁移,其官方网站也提供了相应的迁移指南。另外一个常见的问题是和Spring AOP 相关的(如事务、安全),这在官方网站的FAQ 中也有说明。

 

 

 类似资料: