`
TonyLian
  • 浏览: 401794 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用Sping发布WebService

阅读更多

【原创】用Sping发布WebService


    我的需求是这样的:系统已经成型,仅仅通过基础架构的很小变化,达到将服务开放为WebService的目的。

1、不用或几乎不用修改已有代码

2、简单的xml配置

3、通用性强,各种开发环境皆可访问

4、参数与返回型都要支持DTO(POJO)


    以上四点需求,看起来很简单,可想而知各种Java的WebService方案应该都能够满足。但是,在实际借助网络搜索答案的时候却发现,能搜到的帖子,基本都是相互转帖的,所有的例子几乎一样,就那么2、3篇。


    虽然看了几种实现Webservice方法的比较的帖子,笔者认为与Spring整合的话,CXF比较好,而且似乎有后来居上,掀翻Axis/Axis2的趋势。但我还是分别实践了一下Axis/Axis2/CXF([size=x-small;]Celtix、XFire只看了看帖子,既然已经合并为CXF了,就没有再去实践[/size]),也亲身体验了一把。最终还是初步选定了CXF,下面谈一点体会:


1、其实Axis和Axis2都是可以与Spring很简单的整合的,网上的帖子说不能,这一点我有些质疑。

2、速度我没有比较,网上说CXF比Axis1快4-5倍

3、既然有了Axis2,而且是重新设计的,完全替代Axis,所以Axis就没有仔细琢磨,仅仅调通了一次,就不多说了

4、Axis2的略势(仅仅从开发方便性来说,性能、通用性等尚未关注)是:

4.1、配置文件方式复杂,要求在WEB-INF下建立servers目录,里面是每个WebService各一个目录,各WebService的目录里再有META-INF目录,最后在里面放services.xml。一个WebService就要一个xml配置文件不说,还要复杂的目录结构

4.2、jar包超多。Axis1都打到一个jar包里了,足足15M,Axis2为了让jar包变小,分工明晰,分解了jar包,但是也太多了,足足62个,这还不算axiom的。为他瘦身就要花一番功夫(我不喜欢把所有的jar都一股脑的扔到lib里,能少一个就少一个)

4.3、用.Net做Client访问返回的DTO中的DTO类型出现错误。比如,返回一个department(部门),此对象除id、name等String型属性外,还有List employees属性。我的服务返回的department.employees明明只有一个对象,而Client端得到的却显示List有3个内容,因为Employee有3个属性(id、name、age),分别为string、string、int


5、CXF的略势(仅仅是我认为的):

5.1、CXF要求注释语法,而修改现有代码是我不愿意看到的

5.2、作为妥协,仅仅在接口中使用最简单的注释@WebService,其他非必须的地方都不写注释。导致生成的WebService的名称、命名空间、DTO的类型都由CXF自行命名,尤其是DTO的类名,都是小写开头的,非常别扭。

5.3、从暴露出来的wsdl看,只有SOAP1.1协议,而Axis2还有SOAP1.2和普通Http


以上就是我初步实践的比较结论,综合看,CXF还是有优势的。尤其是Axis2的4.2是个致命问题,不知道是不是我没有调试好,但似乎也看到一篇帖子说Axis2在DTO(自定义类型)的传递上不如CXF。

5.1、5.2问题习惯就好了,5.3也不是大问题,用1.1反而是稳妥的,兼容性更好的。


以下就详细分析一下CXF,例子代码我就尽量不大段的贴了,搜索一下有的是。


接口定义:

@WebService(name = "UserService",targetNamespace = Constants.WS_NAMESPACE) 
public interface UserWebService { 
    @WebResult(name = "user") 
    public UserDTO getUser(@WebParam(name = "userId") Integer userId) throws FaultException; 
} 

 

  • @WebService 必须,(name="UserService")可选,配置Service的名称,默认为类名。targetNamespace可选,默认为http:// package的倒序,可在一个自己的Constants里定义统一的namespace.
  • 默认接口的所有方法均输出为WebService。
  • @WebResult 可选,配置方法的返回值在WSDL的名称,CXF默认为result。
  • @WebParam 可选,配置参数在WSDL的名称,CX比较笨,不会反射,默认为arg0,arg1....
  • @WebMethod 可选,有一个方法有此注释,则其他无注释的方法非WebService。



接口实现:

@WebService(endpointInterface = "xxx.xxx.service.UserWebService",targetNamespace = Constants.WS_NAMESPACE) 
public class UserWebServiceImpl {
    //...
}

 

@WebService(endpointInterface="")  可选,指定实现的接口。接口是对外的,必须通过注释来声明,而Impl是内部的,声明是可选的。


DTO:

@XmlType(name = "User") 
public class UserDTO { 
    //属性及setter/getter方法... 
} 

    • @XmlType(name = "User")  可选的 
    • JAXB的智能化较高,基本上不需要手工映射。 
    • 默认的@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER )根据公共getter/setter与公共属性反射(XmlAccessType.PROPERTY根据getter/setter反射,XmlAccessType.FIELD 根据成员变量反射)
    • 如果有需要注释@XMLElement,@XMLAttribute,需配合XmlAccessorType定义,默认的PUBLIC_MEMBER,需要在getter/setter上定义,如果要写在成员变量上定义,则XmlAccessType改为FIELD。
    • @XmlType(name = "User") 指定WSDL上的类型名称,否则CXF奇怪,DTO的类名是小写开头的。
    • @XmlTransient 可以注释某个字段,取消该字段的反射。

 


总结一下:

    1.统一:每一个接口函数,每一个DTO类都需要定义NameSpace,否则CXF会以类的pacage名倒序作为namespace,大幅提高引发命名空间的复杂度。最好在Constants类里统一定义。

    2.接口: CXF比较笨,所以还需要注释每个方法的参数名。否则会以arg0,arg1命名,用SoapUI 等工具看SOAP包时比较痛苦。(Axis2也是arg0,arg1)
        在ServiceImpl中,最好命名serviceName,否则默认会议类名+Service来命名,如UserManagerServiceImplService,比较难看
    3.DTO:用@XmlType定义 DTO名,否则名称默认小写,在.Net下生成的代码,类名都是小写的,超奇怪。



最后要着重指出一点,在网上能搜索到的N多帖子都是如出一辙,但是估计第一个人犯了错误,而后来者都是不负责任的粘贴!!估计他们都是没有经过自己测试的!太误人子弟了!!


这就是 Server端 作为Spring和CXF桥梁的那个xml配置文件中的写法,引用一段网上的帖子:

在spring-cxf.xml配置发布的web service

<!-- 上半段省略 -->
    <bean id="hello" class="test.HelloWorldImpl" />  
    <jaxws:endpoint id="helloWorld" implementor="#hello"  
        address="/HelloWorld" />  
</beans>
注意: id:指在spring配置的bean的ID.

Implementor:指明具体的实现类.

Address:指明这个web service的相对地址

 
 

请注意这里一共犯了两个错误:

1、id,作为标签的id,它当然是这个endpoint的id,不可能是“指在spring配置的bean的ID”

2、implementor用#引用了上面声明的一个bean,其实implementor=的引用才应该指向在spring配置的bean的ID,spring-cxf.xml中不用也不该再定义一个bean了


正确的写法是:

假设Spring的配置文件applicationContext.xml中定义了一个bean

<bean id="helloWorld" class="test.HelloWorldImpl">
        <property name="userDao">
            <ref bean="userDao" />  <!-- 这里注入一个DAO -->
        </property>
</bean>

 

spring-cxf.xml应该这样写:

    <jaxws:endpoint id="helloWorldEndpoint"
    	implementor="#helloWorld"  <!-- 这里是与spring定义的bean呼应的 -->
        address="/HelloWorldService" />    
  </beans> 

 
试想,如果在implementor参数里指定具体实现类,那spring注入时的“接口指向用具体实现类”还有什么意义呢?
最初的作者仅仅调试了一个HelloWorld就草草落笔,他们并没有仔细观察,当客户端来访时,服务器是新实例化了一个服务呢?还是从spring已经注入好的bean中get一个呢?
显然我们要的是后者的效果,而错误的写法确实前者的效果,虽然HelloWorld能通,但是稍复杂一点,比如sping的bean中又注入了其他bean,那么一下就能发现错误了,因为错误的写法是另外实例化了一个bean,由于他是在错误的spring-cxf.xml中定义的,自然没有写property。


所以写博客、发帖子,都应该本着负责和科学的态度,不能人云亦云,尤其是技术贴,自己没有验证的,请不要Ctrl-C / Ctrl-V !

 

 

 

----------------------一条4年半后的分割线-----------------------------------------------------------------------------

 

今天,大约此贴发帖后4年半的一天,看到一位网友的回复,我又看了一遍这篇文章。

于是想补充一点,后来经过进一步实践,我早已达到了帖子首部提出的4点要求,尤其是第一点,

已经可以做到丝毫不修改原有代码既可以发布WebService。

就是说不需要使用注释的方式了修改代码了。

 

只需要在配置文件中加入

<?xml version="1.0" encoding="UTF-8"?>   
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:simple="http://cxf.apache.org/simple"
    xmlns:soap="http://cxf.apache.org/bindings/soap"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    	http://www.springframework.org/schema/beans/spring-beans.xsd
    	http://cxf.apache.org/core
		http://cxf.apache.org/schemas/core.xsd  
		http://cxf.apache.org/simple    
		http://cxf.apache.org/schemas/simple.xsd">  
    <import resource="classpath:META-INF/cxf/cxf.xml" />    
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />    
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />  

    <bean id="aegisBean" class="org.apache.cxf.aegis.databinding.AegisDatabinding" />  
  
    <simple:server id="webServiceUserAccountService" serviceClass="com.xxxx.service.UserAccountService"  
        address="/UserAccountService">  
        <simple:serviceBean>  
            <ref bean="userAccountService" />  
        </simple:serviceBean>  
        <simple:dataBinding>  
            <ref bean="aegisBean" />  
        </simple:dataBinding>  
    </simple:server>  

</beans> 

 这样就把原来一个普通的【userAccountService】开放为WebService了。

每增加一个WebService,在这个配置文件里增加一段<simple></simple>就可以了。

记着在applicationContext.xml中引用这个xml哦。

 

最后别忘了在web.xml中加上CXF的监听

    <servlet>  
        <servlet-name>CXFServlet</servlet-name>  
        <servlet-class>  
            org.apache.cxf.transport.servlet.CXFServlet  
        </servlet-class>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>CXFServlet</servlet-name>  
        <url-pattern>/webservice/*</url-pattern>  
    </servlet-mapping>

 

 ----------------------一条又过了半年多的分割线-----------------------------------------------------------------------------

 

今天又看到了这个帖子,这半年间,我又优化了一下,这个WebService的发布方法。

 

两条分割线之间的方法其实已经很好了,最大的优点就是配置简单,且对代码零污染。

 

但是,我也发现它的一点问题,就是被开放为WebService的原Service的所有方法都会被开放出来。

那位说了,不就是为了都开放出来吗?不想开放的方法改到另外一个服务中不就行了。

其实,问题可能不出在业务方法上,而是我们的Service的父类中的一些系统级方法,

比如 commit, rollback 之类的。

这些方法开放出去,显得那么不让人放心。

 

那么我们就需要改一下配置文件,<simple:Server>标签改为<jaxws:endpoint>标签。

这样做后,需要一点点的对代码的污染,就是在想要开放为WebService的Service的接口中,

(主意只是接口中,实现类不需要)

给接口定义加一个 @WebService 的注解

(如果业务方法也有一些想开放的,一些不想开放的,又不愿意应为开不开放而破坏原有的

逻辑把这些方法重新分到不同的Service中,那么还可以使用方法级的注解)

 

这样,因为父类中定义的方法(commit, rollback等)没有注解,就不会开放到WebService中了。

 

 

	<jaxws:endpoint id="webUserAccountService" implementorClass="cn.xxxxx.service.UserAccountMasterDataService"  
        address="/UserAccountService">  
		<jaxws:implementor>  
			<ref bean="userAccountService" />  
		</jaxws:implementor>  
		<jaxws:dataBinding>  
			<ref bean="aegisBean" />  
		</jaxws:dataBinding>  
	</jaxws:endpoint>
 

 

import javax.jws.WebService;
@WebService
public interface UserAccountService extends BaseService{
 
这样,我们就保护了BaseService中声明的方法不被一同开放为WebService了。
 
分享到:
评论
2 楼 LoveStart 2014-10-17  
写博客、发帖子,都应该本着负责和科学的态度,不能人云亦云,尤其是技术贴,自己没有验证的,请不要Ctrl-C / Ctrl-V !
1 楼 LoveStart 2014-10-17  
强烈支持最后一句话,技术贴 烂拷贝 烂粘贴 真是害了不好人的时间啊。

相关推荐

    jws与spring发布WebService

    【标题】"jws与spring发布WebService"涉及的是在Java Web Service(JWS)和Spring框架结合下,如何创建和部署Web服务。Web服务是一种基于网络的、平台无关的交互方式,它允许不同系统间的应用进行数据交换。JWS是...

    发布webService服务接口与spring整合教程

    Spring支持基于注解的Web Service发布,如使用`@WebService`和`@WebServiceClient`。你也可以使用Spring-WS或Apache CXF等库来创建WSDL并部署服务。 4. **测试和调试**:确保编写了单元测试来验证Web Service接口的...

    cxf与spring发布WebService

    【标题】:“CXF与Spring发布WebService” 在Java世界中,发布Web服务是常见的系统间交互方式,CXF和Spring框架结合使用可以高效地实现这一功能。CXF(CXF:CXF Extends Fuses)是一个开源的服务栈,主要用于构建和...

    cxf+spring发布webservice和restservice

    本项目“cxf+spring发布webservice和restservice”专注于利用Apache CXF框架与Spring框架结合,实现这两种服务的发布。Apache CXF是一个开源的、功能丰富的服务栈,它使得开发者能够轻松地构建和部署SOAP和RESTful ...

    在自己的项目中利用axis2+spring发布webservice与客户端调用包括session

    标题中的“在自己的项目中利用axis2+spring发布webservice与客户端调用包括session”指出的是一个关于在实际项目开发中如何使用Axis2和Spring框架来发布Web服务,并且涉及了Web服务客户端调用以及会话(session)...

    axis2+spring webservice

    描述中提到的“简单例子:axis2整合spring发布webservice”,意味着我们将学习如何将这两个框架结合,以便通过Spring来管理和控制Web服务的生命周期,同时利用Axis2的Web服务处理能力。此外,“以及session的管理”...

    Spring+CXF 发布WebService服务

    本文将深入探讨如何使用Spring和CXF来发布WebService服务。 首先,Spring是一个开源的Java平台,它提供了全面的编程和配置模型,用于简化企业级应用的开发。Spring框架的核心特性包括依赖注入、面向切面编程(AOP)...

    cxf+spring实现webservice

    4. **服务注册与发布**:使用Spring配置的`JAXWSServerFactoryBean`或`JAXRSServerFactoryBean`,将服务接口和实现绑定到特定的URL上,发布Web服务。 5. **客户端调用**:在需要消费Web服务的项目中,可以使用...

    Spring.Net开发WebService

    在这个特定的话题中,我们将深入探讨如何利用Spring.NET来开发Web服务,尤其是WebService。WebService是一种基于XML的、平台和语言无关的通信协议,它允许不同的应用程序之间进行交互。 首先,我们需要理解Spring...

    CXF和Spring搭建webservice代码

    【CXF和Spring搭建Web服务代码详解】 在Java开发领域,CXF和Spring框架的结合是构建高效、灵活的Web服务的常见选择。CXF是一个开源的SOAP和RESTful Web服务框架,它允许开发者轻松地创建和消费Web服务。而Spring...

    spring集成axis发布webservice源码

    spring集成axis发布webservice源码 spring集成axis发布webservice源码 spring集成axis发布webservice源码 spring集成axis发布webservice源码

    Xfire Spring Hibernate 发布WebService(源码)

    Xfire Spring Hibernate 发布WebService(源码) Xfire1.2 Spring 2.0 Hibernate 3 发布WebService 一、准备工作 1、下载安装MyEclipse6.5 2、下载安装MySQL Server 5.1 3、下载MySQL驱动 mysql-connector-java...

    Spring整合CXF步骤,Spring实现webService,spring整合WebService

    总的来说,Spring整合CXF的步骤主要包括配置CXF,定义服务接口和实现,然后在Spring中发布这些服务。通过这样的整合,你可以享受到Spring带来的便利,同时利用CXF的强大功能来构建高质量的Web服务。在实际开发中,还...

    使用xfire+spring构建webservice

    标题“使用xfire+spring构建webservice”指出的是一个关于如何利用XFire和Spring框架创建Web服务的教程。XFire是早先的一个用于构建Web服务的开源Java库,它简化了SOAP(简单对象访问协议)服务的开发。而Spring框架...

    部署WebService服务(cxf,spring)

    本篇将深入探讨如何利用CXF和Spring来部署WebService服务。 首先,CXF全称是CXF Commons eXtensible Framework,它是一个Java Web服务框架,支持多种Web服务标准,如SOAP、RESTful(Representational State ...

    Apache CXF2+Spring2.5轻松实现WebService

    本教程将深入探讨如何利用Apache CXF 2与Spring 2.5来构建和使用WebService。 首先,让我们理解这两个组件的基本概念。Apache CXF是一个全面的服务框架,它支持多种Web服务规范,如SOAP、RESTful、WS-*等。它提供了...

    CXF+Spring发布webservice服务的例子

    当将两者结合使用时,可以方便地在Spring应用中发布和消费Web服务。本例主要探讨如何使用CXF和Spring4.1来发布一个基于SOAP的Web服务。 首先,我们需要确保环境已经准备就绪。在项目中引入CXF和Spring的依赖库,...

    CXF结合Spring发布Json格式WebService示例

    本实例工程使用Apache CXF组件快速开发WebService。基于Spring框架,使用了Maven项目,但由于时间原因,只使用了Maven Project的框架,还是使用lib文件夹存放所需的cxf库,传入传出对象支持Json格式。

    WebService验证与Spring整合

    在IT行业中,Web服务是应用程序之间进行通信的一种标准方法,而Spring框架是Java开发中广泛使用的轻量级框架。本文将深入探讨如何将WebService验证与Spring框架整合,以实现高效、安全的服务调用。 首先,让我们...

    cxf整合spring发布webservice(源码)

    以上就是Linux环境下,使用CXF整合Spring发布Web服务的基本流程和关键知识点。实际开发中,可能还需要根据具体需求进行更深入的配置和定制,例如支持WSDL第一或第二样式、处理MTOM和SwA等复杂数据交换格式。通过这种...

Global site tag (gtag.js) - Google Analytics