怎么样使用xfire快速发布WebService?
在经历过早年Delphi,C++,Java等不成熟环境中开发WebService的折磨之后,接触ASP.NET的最大感触,就是WebService的开发门槛被大大降低了。无需对SOAP或基本架构有任何了解,仅需简单的定义几个Attribute即可,所有的dirtywork都由ASP.NET在后台自动完成。例如:
|
而这一巨大的生产力进步,现在开始在Java领域也可直接享用。例如:
|
在项目搭建时完成一次性的配置之后,我们绝大多数的工作就是定义WebService接口,设定WebService的发布方式。然后就是实现此接口并放入spring中进行管理,例如:
|
这一神奇效果的幕后英雄就是codehaus最新发布的xfire1.0SOAP框架。
与Axis等现有实现相比,xfire的最大优点就是改用StAX基于流的XML分析引擎,加上其SOAP协议栈实现上的精巧设计,能够带来比Axis快2-5倍的性能提升。具体的性能评测数据,可以参考一些第三方评测结果。
而在功能上xfire也毫不逊色,其Features&Goals里面充满了各种bigwords。
* Support for important Web Service standards - SOAP, WSDL, WS-I Basic Profile, WS-Addressing, WS-Security, etc.
* High performance SOAP Stack
* Pluggable bindings POJOs, XMLBeans, JAXB 1.1, JAXB 2.0, and Castor support
* JSR 181 API to configure services via Java 5 and 1.4 (Commons attributes JSR 181 syntax)
* Support for many different transports - HTTP, JMS, XMPP, In-JVM, etc.
* Embeddable and Intuitive API
* Spring, Pico, Plexus, and Loom support.
* JBI Support
* Client and server stub generation
* JAX-WS early access support
与Axis,Glue以及ActiveSOAP的详细功能对比,可以参考StackComparison文档。
下面先就xfire基础架构以及与spring集成的基本情况大概做一个简单介绍,回头有时间再整一个xfire与axis实现架构的横向对比。
与axis很相似xfire在架构上也可以大概分为Service,Transport和Invoker三个层面。
Service层是xfire架构的静态基础,负责完成对服务的注册及其管理。核心的ServiceRegistry接口完成对服务自身的生命期管理,如注册/注销/获取等等;而ServiceFactory接口则负责从具体的POJO类型,生成实现Service接口的可被管理的服务代理。
Transport层则是xfire的外部IO处理系统。由TransportManager接口对具体的Transport接口实现进行管理,默认提供了基于pipe的LocalTransport和基于Http协议的SoapHttpTransport。理论上可以任意进行扩展,例如xfire发布包中还提供了基于JMS和XMPP的实现。
Invoker则是xfire的动态调用层,负责在Transport层接受到请求后,解析内容、调用合适服务并最终返回SOAP封包给调用者。运行时Invoker负责维系Service和Transport之间的联系。
因此一个服务的生成和注册往往类似如下代码:
|
最基本的XFire接口,实际上就是getServiceRegistry()和getTransportManager()的封装。
xfire中另一块核心的思想,就是其灵活而强大的binding机制,负责完成Java类型与SOAP消息的双向转换。xfire仅仅内建就支持POJO(Aegis),Castor,JAXB1.1,JAXB2.0和XMLBeans多种模式,你可以根据需求选择从全自动POJO生成,到全手工xsd文件定义的不同方式。
而对使用spring环境的开发者来说,要提供上述这一系列支持,只需要直接将xfire-spring工程中的fire.xml文件包括到applicationContext.xml中,即可直接获得完整的xfire架构。
|
不过相比于通过xml文件定义服务来说,我更倾向于直接用Annotation方式在代码级完成定义。xfire-annotation提供了对Java5Annotation和apachecommon-attribute的完整支持。例如上述例子中在javadoc里定义的@@标签,就是用于使用xdoclet生成common-attribute支持的。
因为common-attribute并非编译器一级提供支持,因此要在编译之前增加一道处理过程。个人推荐直接使用maven进行管理,当然也可以在ant中直接配置task。maven1.x的具体配置方式如下:
|
增加了以上配置后,在maven编译时,会自动增加一个common-attribute支持文件的编译过程,并在target/commons-attributes下生成类似ServerVariables$__attributeRepository.java的文件,以存储@@标签中指定的Metadata。在eclipse等IDE中,我们可以直接把这些目录添加为源码目录。
而在为了使用common-attribute定义的元信息,xfire提供了Jsr181HandlerMapping来自动完成服务映射支持。
|
因为xfire同时需要支持Java5模式和common-attribute模式的元信息,所以对元信息的获取被封装到annotations.commons.CommonsWebAttributes和annotations.jsr181.Jsr181WebAnnotations中,以便根据实际使用进行配置。而xfire和xfire.typeMappingRegistry则是引用前面提到的xfire.xml中定义的基础接口和类型映射支持。
Jsr181HandlerMapping是从spring提供的ApplicationObjectSupport上基础出来的,它实现了ApplicationContextAware接口,因此会在bean定义被加载完成后,调用其setApplicationContext方法,并进而调用其initApplicationContext方法完成初始化。
Jsr181HandlerMapping.initApplicationContext方法中,会遍历当前ApplicationContext的所有父容器,调用processBeans方法处理器其bean定义。而在processBeans中针对每个bean,检查其是否为singleton的非抽象对象,且定义了WebServiceAnnotation;如果是则构造bean并以前面提到的方式进行注册。
值得注意的是,xfire1.0乃至最新CVS版本,在这块的实现都有一个严重bug,没有对abstractbean进行处理。其代码中直接用beanFactory.getBean(beanNames[i])试图获取实例,如果bean是singleton的abstract模式,则会导致spring抛出异常。可以将其检测代码改成如下方式:
|
此bug及修复代码已提交到xfire的JIRA上,待进一步确认。
而在具体对bean是否定义服务的判断上,xfire1.0中的支持实际上也是很不完整的。象最上面例子中,由ServerVariables定义服务接口,ServerVariablesImpl中实现服务的方式,直接在xfire下是无法使用的。关键原因在于xfire-annotations工程在定义WebService等annotation时,没有指定其可继承性。
改进方法也很简单,在org.codehaus.xfire.annotations.commons包的WebService,WebMethod,WebResult,WebParam等annotation定义中,类一级增加一个@@org.apache.commons.attributes.Inheritable()标签即可。common-attribute在判断是否存在某个annotation时,会自动将具有Inheritable属性的自定义属性,继承到其所有子类。这样一来就可以很完美的解决通过接口定义服务的问题。此改进也已提交到xfire的JIRA上,待进一步确认。
完成了这些基础性工作后,剩下的任务就非常简单了。根据xfire的ServletSetup文档,在web.xml中增加相关servlet的定义,接管/service/**或其它URL。
|
然后就可以通过http://localhost:8080/xfire/services/WeatherService?wsdl 类似的方式访问wsdl或调用WebService了。详细的配置请参考xfire相关文档。
完整的xfire支持bean配置大致如下:
|
本文地址:http://www.45fan.com/dnjc/69854.html