45.2. 在Apusic AS中开发WS

在Java EE环境中,按照JWS规范的规定,端口组件(Port Component)是指一个Web服务的服务器端视图,端口组件也称端口(Port),每一个端口组件对应着WSDL中定义的一个端口地址,并在该地址上服务于WSDL里端口类型(PortType)中声明的操作请求。

端口组件Java EE环境中WS所定义的编程模型包含如下构件:

  1. WSDL文档:并非严格必须,WSDL文档是可以自由发布给第三方的标准Web服务描述。WSDL文档和服务端点接口之间必须符合JAX-RPC/JAX-WS规范中定义的WSDL与Java间的映射规则。

  2. 服务端点接口:Service Endpoint Interface(SEI),是WSDL中的端口类型在Java语言平台上的映射。该接口定义了应该由服务实现Bean所实现的方法。

  3. 服务实现Bean:Service Implemention Bean(SIB),一个用于提供Web服务业务逻辑的Java类。表明了端口组件与JavaEE容器间的契约,使得Web服务业务逻辑能够与容器所提供的服务交互。服务实现Bean应该同SEI中定义的方法和签名保持一致,但不要求SIB在Java语法上实现SEI。在Java EE容器环境中有两种类型的服务实现Bean:托管于Web容器中的JAX-RPC/JAX-WS POJO和运行在EJB容器中的无状态会话Bean(Stateless EJB)

  4. 安全角色引用:Security Role References,端口声明在部署描述符中的角色名将在部署时被映射为物理角色,从而允许服务提供实例级的安全检查。

开发人员编写服务实现Bean,细心处理SEI与WSDL之间的映射,然后由部署人员在部署描述符中声明端口组件,及其所关联的包含端口类型和服务绑定描述的WSDL文档,这是JAX-RPC时代典型的WS开发方式,耗时费力。如果使用JAX-WS,部署描述符将是可选的,大部分配置、映射与定制将由对业务代码和使用情况更为熟悉的开发人员通过加诸于SEI或SIB上的注解完成,如若必要才通过部署描述符进行调整,这种开发方式显然更为便捷。

作为企业级的中间件产品,金蝶Apusic应用服务器出于兼顾功能与实用性的考虑,加强了对JAX-WS的支持,同时全面兼容JWS规范(JSR-109),在Apusic应用服务器中开发、部署、发布和使用Web服务将是快捷而高效的。

通常来说,Web服务的开发有两种方式:

  1. 自顶向下,以独立的的WSDL服务描述为蓝本,基于具体平台开发兼容的服务业务逻辑,这种方式主要适用于现有系统整合与业务集成的场景。

  2. 自底向上,从代码开始有目的地构建并对外发布Web服务,这种方式主要适用于以Web服务的方式对外提供增值服务。

两种方式的选择取决于是否预先就存在独立的WSDL服务描述,其根本要求是保证业务代码与服务描述的语义兼容,本质上并无区别。

由于Apusic应用服务器完全兼容规范、且在Apusic上开发部署Web服务相当简单,因而我们并没有对此提供独立开发工具的支持,当今所有支持企业级开发的工具完全能胜任此项工作,这也包括金蝶中间件公司早先提供的基于Eclipse的开发工具——OperaMasks Studio。

下面,我们将以一个Hello Web服务为例,采用自底向上的开发方式演示在Apusic应用服务器中开发、部署和发布符合规范Web服务的基本过程:

45.2.1. 通用构件

为了简化开发步骤、降低使用复杂度,部署的Apusic应用服务器中的Web服务端口组件可选地可以提供下列通用构件:

  1. WSDL,服务描述

  2. SEI,服务端点接口

  3. webservices.xml,部署描述符

45.2.1.1. WSDL

可以在应用中包含服务的WSDL描述,然后通过JAX-WS中定义的类型级别@WebService注解的wsdlLocation属性引用此描述,或者通过部署描述符webservices.xml配置此描述,SEI和SIB必须同WSDL中的内容保持语义兼容,否则应用部署将失败。

如果没有在应用中提供WSDL,Web服务成功发布后,Apusic应用服务器将为每一个Web服务自动生成对应的WSDL,并在服务的绑定地址上按照一定的URL模式对外提供web访问。得到此WSDL的客户端将能成功访问相应的Web服务。

由于是自底向上开发方式,WSDL内容可参照服务发布完成后产生的WSDL文档。

WSDL规范链接:http://www.w3.org/TR/wsdl

45.2.1.2. SEI

SEI是WSDL服务描述中PortType部分对应于Java平台的接口定义,SEI中的方法对应于PortType中定义的操作,SEI需要与提供的WSDL保持语义相同。

端口组件SEI在Apusic应用服务器中也是可选的。如果没有为SIB显式指定SEI,服务器将自动为SIB生成默认SEI,该默认SEI方法组成如下:

  1. 所有存在注解@WebMethod且exclude属性为false(默认值)的public方法。

  2. 否则,所有非继承自Object类的public方法,排除包含@WebMethod注解且exclude属性为true的那些。

本手册中所使用的SEI代码如下:

package com.apusic.ws.endpoint.sei;
import javax.jws.WebService;
@WebService
public interface HelloSEI {
    public String hello(String input);
}

说明:

  1. 必须通过注解@WebService标记一个接口是某个Web服务在JavaEE环境下的SEI。

  2. 接口中的所有方法代表了Web服务所提供的操作集合,可通过方法上的@WebMethod注解对这些操作进行定制

Java与WSDL 1.1之间的映射规则可参考JAX-WS规范。

45.2.1.3. webservices.xml

在JAX-WS规范中,部署描述符webservices.xml是可选的,其原有功能已由JAX-WS或JWS规范中的相关注解取代。

但另一方面,可以通过该部署描述符在部署时(而不是开发期)对端口组件进行一定的装配,如服务SEI或WSDL引用等,因为相对于注解,该部署描述符中的内容具有更高优先级。本示例未提供webservices.xml。相关结构与内容可参考JSR-109规范。

下面将要介绍本示例中所使用到的SIB,不同的SIB运行于不同的容器中,使用不同的容器服务,提供Web服务的业务逻辑。SIB是区分不同端口组件类型的关键。

45.2.2. JAX-WS POJO

本示例中所使用的JAX-WS POJO服务实现Bean代码如下:

package com.apusic.ws.endpoint.jaxws;
import javax.jws.WebService;
@WebService(endpointInterface = "com.apusic.ws.endpoint.sei.HelloSEI")
public class HelloPOJO {
    public String hello(String input) {
        return "hello " + input + " from jaxws pojo endpoint";
    }
}

说明:

  1. 通过@WebService注解声明类HelloPOJO是一个SIB

  2. 通过endpointInterface属性引用SIB所实现的SEI,从代码可以看出,HelloPOJO并不需要在Java语法上实现HelloSEI,只须在方法签名上同HelloSEI保持一致。(其实只需要在WSDL语义上同HelloSEI保持一致即可)

  3. 引用SEI后,在生成的WSDL行,SEI将对应于服务抽象定义的部分,如类型、消息和接口类型;SIB则主要被映射到WSDL定义中的绑定、服务和端口部分。上述各部分内容都可以通过JSR-181或JSR-224中定义的注解进行定制。详请参照相关规范。

JAX-WS POJO运行于web容器中,和其它运行在web容器中的应用组件一样,也能够得到由容器所提供的线程池、请求分发、资源注入、生命周期回调等服务。详情请参考JSR-109中的相关规定。

至此,一个JAX-WS POJO Web服务端口组件开发完成。

接下来,进行部署、发布和测试:

  1. 将上述代码编译后打包到任一Web应用war包中(或者可以直接使用目录部署,使用ear包同样可行),本示例将其加入一个context-root为hello的web应用中。

  2. 启动应用服务器,将上述war包复制到所启动域的applications目录下,应用将被自动部署。

  3. 打开IE浏览器,输入地址http://localhost:6888/hello/HelloPOJOService?wsdl(假设应用部署在本地),可以看到如下由应用服务器自动生成的服务WSDL描述:

  4. 使用Soap-UI测试Hello Web服务:

    1. 打开Soap-UI,选择File-->New soapUI Project,界面如下图:

    2. 在Project Name一栏任意输入,如Apusic JAX-WS POJO Test,在Initial WSDL/WADL一栏输入上述生成的WSDL web访问地址,选择Create Requests,如下图:

    3. 单击OK,界面左侧工程列表栏出现新建的soapUI工程,如下图:

    4. 双击左侧Request 1节点,右侧工作区间出现测试请求响应显示界面,如下图:

    5. 在工作区间左侧的请求区域的arg0元素中输入待测试消息如test,并单击上方的提交按钮,右侧响应区域将显示成功调用Hello Web服务后的响应消息,如下图:

  5. 测试通过。

    下面,将演示开发Hello Web服务的Stateless EJB SIB版本:

45.2.3. Stateless EJB

开发一个普通的EJB 3 stateless EJB,并为其添加@WebService注解,引用SEI,代码如下:

package com.apusic.ws.endpoint.ejb;
import javax.ejb.Stateless;
import javax.jws.WebService;
@Stateless
@WebService(endpointInterface = "com.apusic.ws.endpoint.sei.HelloSEI")
public class HelloEJB {
    public String hello(String input) {
        return "hello " + input + " from stateless ejb endpoint";
    }
}

至此,一个Stateless EJB Web服务端口组件开发完成。上述SIB运行在EJB容器中,能够使用EJB容器所提供的各种服务,同时对外响应SOAP请求提供Web服务。

将上述SEI和SIB代码编译并打包到一个jar(或ear)包中,加入应用服务器的applications目录自动部署,其部署、发布与测试的过程与JAX-WS POJO端口组件类似。唯一不同在于其WSDL访问地址为:http://localhost:6888//HelloEJBService/HelloEJB?wsdl

可以看到,由于JavaEE相关规范中对WS编程模型的简化,以及注解、元数据映射等相关技术的引入,更得益于Apusic应用服务器对规范的完美支持,在Apusic应用服务器中开发和使用Web Service确实是相当快捷高效的。

另一方面,在一个简单的入门级示例中,Apusic应用服务器所支持的其他定制功能和高级特性必然难以尽数体现。但正如前文所说,Apusic应用服务器完美兼容规范,其它地方随处可见的JWS典型用法一般都适用于Apusic应用服务器,这也是无需更多琐碎示例的缘由。