开发者社区> otteras> 正文

通向架构师的道路(第十天)之Axis2 Web Service(一)

简介: 一、Axis2简介 1.1 介绍Axis2 Axis框架来自 Apache 开放源代码组织,它是基于JAVA语言的最新的 SOAP 规范(SOAP 1.2)和 SOAP withAttachments 规范(来自 Apache Group )的开放源代码实现。
+关注继续查看

一、Axis2简介

1.1 介绍Axis2

Axis框架来自 Apache 开放源代码组织,它是基于JAVA语言的最新的 SOAP 规范(SOAP 1.2)和 SOAP withAttachments 规范(来自 Apache Group )的开放源代码实现。有很多流行的开发工具都使用AXIS作为其实现支持Web服务的功能,例如JBuilder以及著名的Eclipse J2EE插件Lomboz。AXIS的最新版本可以从 http://ws.apache.org/axis/index.html下载。

下载下来后直接解压即可用了。下图是AXIS核心引擎的体系结构图:

整个AXIS项目包括以下几个部分:

ü   消息流子系统

消息流子系统提供了灵活的消息传递框架,这个消息传递框架包括处理程序、链、序列化程序和反序列化程序。处理程序是一个处理请求、响应和故障流的对象。处理程序可被组合在一起成为链,而且可以使用一个灵活的部署描述符来配置这些处理程序的顺序。

ü   传输框架子系统

提供了一个传输框架,这个传输框架可以帮助您创建自己的可插式传输发送器和传输侦听器。

ü   数据编码子系统

AXIS完全按照 XML Schema 规范提供各种数据类型的自动序列化,并且提供功能扩展接口来使用您自己定制的序列化器和反序列化器。

ü   其他

AXIS完全支持 WSDL 以及日志记录、出错以及故障处理机制。它同时提供一些工具用来讲WSDL文档转换成客户端的调用框架以及根据类来产生WSDL定义文档。

AXIS目前版本支持的标准是:W3C SOAP1.1 和 1.2;WSDL 1.1;SAAJ 1.1(SUN公司:SOAP with Attachments API for Java);JAX-RPC(SUN公司:Java APIfor XML-Based RPC)1.0。

1.2 开发项目中如何选择使用Axis2和其它的WebService

²  如果你的应用程序需要支持多语言即有C++, .net, Java,你应该选择Axis2。

² 如果应用程序是遵循 Spring 哲学路线的话,ApacheCXF 或者Spring WS是一种更好的选择,特别对嵌入式的 Web Services 来说。

一、搭建环境

第一步:

打开Eclipse,建立一个标准的Dynamic Web Project

第二步:

建完工程后,把Axis2-1.4/Axis2-1.4.1解压开来的目录下的axis2-web(如下图),整个拷入你工程的WebContent目录下:

第三步:

把Axis2-1.4/Axis2-1.4.1解压开来的目录下的lib目录里的所有jar导入你工程的WEB-INF/lib目录下,并加载入工程的classpath,如下图

第四步:

在工程和src平级处新建一个目录叫external-lib


第五步:

把tomcat里的用于jsp, servlet解析的两个lib拷入此external-lib目录,并且以“加载外部jar”的方式加入工程的classpath中去

第六步:

在工程的WEB-INF目录下新建一个目录叫services目录。

第七步:

把Axis2-1.4/Axis2-1.4.1解压开来的目录下的repository\modules,modules这个目录,整个拷贝到你工程的WEB-INF目录下。

整个配完的工程结构应如下图所示:

三、    第一个Axis2Webservice之HelloWorld

3.1Service端代码

package org.sky.axis2.helloworld;

 

import org.apache.axiom.om.OMElement;

import org.apache.axis2.AxisFault;

 

import javax.xml.stream.XMLStreamException;

 

public class HelloWorld {

 

         public OMElement sayHello(OMElement element) throws XMLStreamException {

                   element.build();

                   // Secondly the OMElement should be detached from the current OMTree so

                   // that it can be attached

                   // some other OM Tree. Once detached the OmTree will remove its

                   // connections to this OMElement.

                   element.detach();

                   return element;

         }

}

3.2 Service端的Web Service布署文件

然后我们在工程的WebContent\WEB-INF\services\目录下新建一个目录叫HelloWorld的目录,与我们的类同名,在此目录下再建立一个META-INF的目录(大小写必须完全一致),然后在META-INF目录下新建一个services.xml,具体目录结构如下图所示:

Services.xml文件的内容如下:

<service name="HelloWorld">

         <parameter name="ServiceClass">org.sky.axis2.helloworld.HelloWorld</parameter>

    <operation name="sayHello">

        <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>

        <actionMapping>urn:sayHello</actionMapping>

    </operation>

</service>

该布署文件很容易阅读:

1)      它声明了一个WebService的主类叫” org.sky.axis2.helloworld.HelloWorld”;

2)      该WebService有一个Web Service Method,在类中该方法名叫sayHello,它返回一个OMElement为类型的值,接受一个OMElement为类型的参数;(RawXMLINOutMessageReceiver)

3)      sayHello这个对外暴露的WebService方法名为: urn:sayHello

修改web.xml,在里面加入这些东东:

<servlet>
    <display-name>Apache-Axis Servlet</display-name>
    <servlet-name>AxisServlet</servlet-name>
    <servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>/servlet/AxisServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>*.jws</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
  <servlet>
    <display-name>Apache-Axis Admin Servlet Web Admin</display-name>
    <servlet-name>AxisAdminServlet</servlet-name>
    <servlet-class>org.apache.axis2.transport.http.AxisAdminServlet</servlet-class>
    <load-on-startup>100</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>AxisAdminServlet</servlet-name>
    <url-pattern>/axis2-admin/*</url-pattern>
  </servlet-mapping>

3.3 布署Web Service

在Tomcat的webapps目录下建立一个目录叫Axis2Service的目录

然后将整个工程的WebContent目录下的所有东西,全拷贝入这个目录内,启动tomcat。

启动后访问:http://localhost:8080/Axis2Service/axis2-web/

单点:Services这个链接

再点这个HelloWorld链接

我们就可以得到我们的HelloWorld这个WebService的wsdl内容了。

三、    四种不同的HelloWorld客户端

Axis2支持4种类型的客户端:

ü   Block(阻塞式客户端)

传统客户端

ü   Non block(非阻塞式客户端)

又被称为异步客户端,传统客户端被调用后将会被阻塞直到操作完成。这种方式在有很多Web Service需要在一个单一的客户端应用程序中启动时很不可取。一种解决方法是使用Non-Blocking API来调用这些Web Services。Axis2提供给用户一种基于回叫机制的non-blocking API。

ü   双工(双向传输)

以上的机制都使用单一的连接去发送请求和接收响应.这都明显在性能上落后于使用两条连接(单向或双向)进行进行请求和响应的传输 . 因此以上的机制都不能解决长时间运行的交易, 连接将在操作还没完成就会超时. 一种解决方案是使用分开的两条传输连接来传输请求和响应 . 我们叫这种方案为传输层异步。

ü   双工非阻塞(双向且非阻塞传输)

下面我们就来看这四个客户端(此处对于双工传输的客户端代码进行忽略,因为这个写法很简单,我们将着重于描述双工+非阻塞的客户端例子,网上目前几乎没有能够在axis21.4下真正能够运行的“双工且非阻塞”的例子或者是完整代码)。

4.1 传统的客户端HelloWorldWithReturnClient.java

package org.sky.axis2.helloworld;

 

import java.util.Iterator;

 

import javax.xml.namespace.QName;

 

import org.apache.axiom.om.OMAbstractFactory;

import org.apache.axiom.om.OMElement;

import org.apache.axiom.om.OMFactory;

import org.apache.axiom.om.OMNamespace;

import org.apache.axiom.om.OMNode;

import org.apache.axiom.soap.SOAPBody;

import org.apache.axis2.AxisFault;

import org.apache.axis2.addressing.EndpointReference;

import org.apache.axis2.client.Options;

import org.apache.axis2.client.ServiceClient;

import org.apache.axis2.databinding.utils.BeanUtil;

import org.apache.axis2.engine.DefaultObjectSupplier;

public class HelloWorldWithReturnClient {

         private static EndpointReference targetEPR = new EndpointReference(

                            "http://localhost:8080/Axis2Service/services/HelloWorld");

         public void sayHello() {

                   Options options = new Options();

                   options.setAction("urn:sayHello");

                   options.setTo(targetEPR);

                   ServiceClient sender = null;

                   try {

                            sender = new ServiceClient();

                            sender.setOptions(options);

                            OMFactory fac = OMAbstractFactory.getOMFactory();

                            OMNamespace omNs = fac

                                               .createOMNamespace("http://helloworld.axis2.sky.org", "");

                            OMElement method = fac.createOMElement("sayHello", omNs);

                            OMElement name = fac.createOMElement("name", omNs);

                            name.setText("ymk");

                            method.addChild(name);

                            method.build();

                            OMElement response = sender.sendReceive(method);

                            System.out.println(response);

                            OMElement element = response.getFirstChildWithName(

                                               new QName("http://helloworld.axis2.sky.org", "name"));

                            System.out.println(element.getText());

                   } catch (AxisFault e) {

                            System.out.println("------Error Occured------");

                            e.printStackTrace();

                   }

         }

         public static void main(String[] args) {

                   HelloWorldWithReturnClient testClient = new HelloWorldWithReturnClient();

                   testClient.sayHello();

         }

}

注意我加粗或者是加粗标红处的代码,为核心代码。

由于我们使用提Axis2的底层API来调用WebService而并不是像傻瓜式的通过一个wsdl生成Web Service调用句柄,所以我们要对一个WSDL能够有阅读能力。

ü   Axis2中的Webservice的入口

不是: http://localhost:8080/Axis2Service/services/HelloWorld?wsdl这个哦,而应该是:

http://localhost:8080/Axis2Service/services/HelloWorld,不带?wsdl。

ü   看一个wsdl中的namespace是什么:

ü   看一个wsdl中的web service方法名是什么


ü   看一个wsdl的返回结果是怎么样的格式:

为此我们在程序里增加了一行:OMElement response =sender.sendReceive(method);

然后直接:System.out.println(response);

这样,我们可以看到它的返回为:

根据Axis2的OMElement的解析语法我们就可以直接把这个返回的值get出来。

我们甚至可以用opensource的SOAP UI这个工具,来直接得到我们的webservice调用的返回值,并以此返回结果的格式来决定我们如何去解析这个OMElement格式的返回结果:

在工程上单击右键选“AddWSDL”


在弹出对话框中直接把http://localhost:8080/Axis2Service/services/HelloWorld?wsdl加入对方框中的wsdl栏中


点OK生成webservice soap ui调用的客户端如下图

它会生成11Binding和12Binding两个客户端,我们把11Binding的节点展开,双击Request 1,在右边会显示调用的soap样例,在<hel:sayHello>?</hel:sayHello>块中我们把问号替换成Monica,然后点上方“绿色”运行按钮,我们就可以得到调用结果如下图:

因此通过SOAP UI我们也可以测试我们的Web Service。

4.2 非阻塞式HelloWorldWithReturnNonBlock.java

与传统的阻塞式webservice调用不同的是,一旦调用"serviceClient.sendReceive(payload);",客户端将会被阻塞直到操作完成。这种方式在有很多Web Service需要在一个单一的客户端应用程序中启动时很不可取。一种解决方法是使用Non-Blocking API来调用这些Web Services。Axis2提供给用户一种基于回叫机制的non-blocking API。

很多网上使用的“回调”接口都只能在Axis21.3中才能使用,而在Axis21.4中回调接口已经被升级成一个抽象类叫AxisCallBack类了,因此90%目前网上的关于“非阻塞式”的客户端的代码在Axis2中都是跑不起来的,在eclipse ide中会显示“该类/方法已经被deprecated(废弃)”。

因此请注意看笔者的代码,先声明一个用于非阻塞调用的回调(callback)类

HelloWorldNonBlockCB.java

package org.sky.axis2.helloworld;

 

import java.util.Iterator;

 

import javax.xml.namespace.QName;

 

import org.apache.axiom.om.OMElement;

import org.apache.axiom.om.OMNode;

import org.apache.axis2.client.async.AxisCallback;

import org.apache.axis2.context.MessageContext;

import org.apache.axis2.databinding.utils.BeanUtil;

import org.apache.axis2.engine.DefaultObjectSupplier;

 

public class HelloWorldNonBlockCB implements AxisCallback {

         private boolean complete = false;

 

         public void onMessage(MessageContext msgContext) {

                   System.out.println(msgContext.getEnvelope().getBody());

                   OMElement element = msgContext.getEnvelope().getBody()

                                     .getFirstElement();

                   OMElement result = element.getFirstChildWithName(new QName(

                                     "http://helloworld.axis2.sky.org", "name"));

                   System.out.println(result.getText());

                   synchronized (this) {

                            this.notify();

                   }

         }

 

         public boolean isComplete() {

                   return complete;

         }

 

         public void onFault(MessageContext msgContext) {

                   System.out.println(msgContext.getEnvelope().getBody().getFault()

                                     .toString());

                   synchronized (this) {

                            this.notify();

                   }

         }

 

         public void onError(Exception e) {

                   e.printStackTrace();

                   synchronized (this) {

                            this.notify();

                   }

         }

 

         public void onComplete() {

                   this.complete = true;

                   synchronized (this) {

                            this.notify();

                   }

         }

}

有了callback接口,我们来写我们的webservice调用类

HelloWorldWithReturnNonBlock.java

package org.sky.axis2.helloworld;

 

import org.apache.axis2.addressing.EndpointReference;

import org.apache.axiom.om.OMAbstractFactory;

import org.apache.axiom.om.OMElement;

import org.apache.axiom.om.OMFactory;

import org.apache.axiom.om.OMNamespace;

import org.apache.axis2.AxisFault;

import org.apache.axis2.addressing.EndpointReference;

import org.apache.axis2.client.Options;

import org.apache.axis2.client.ServiceClient;

import org.apache.axis2.client.async.AxisCallback;

import org.apache.axis2.context.MessageContext;

 

public class HelloWorldWithReturnNonBlock {

         private static EndpointReference targetEPR = new EndpointReference(

                            "http://localhost:8080/Axis2Service/services/HelloWorld");

         public void sayHello() {

                   OMFactory fac = OMAbstractFactory.getOMFactory();

                   OMNamespace omNs = fac.createOMNamespace(

                                     "http://helloworld.axis2.sky.org", "");

                   OMElement method = fac.createOMElement("sayHello", omNs);

                   OMElement name = fac.createOMElement("name", omNs);

                   name.setText("ymk");

                   method.addChild(name);

                   method.build();

                   Options options = new Options();

                   options.setTo(targetEPR);

                   ServiceClient sender = null;

                   try {

                            HelloWorldNonBlockCB callback = new HelloWorldNonBlockCB();

                            sender = new ServiceClient();

                            sender.setOptions(options);

                            sender.sendReceiveNonBlocking(method, callback);

                            synchronized (callback) {

                                     try {

                                              callback.wait();

                                     } catch (InterruptedException e) {

                                              e.printStackTrace();

                                     }

                            }

                   } catch (AxisFault e) {

                            e.printStackTrace();

                   } finally {

                            if (sender != null)

                                     try {

                                               sender.cleanup();

                                     } catch (Exception e) {

                                     }

                   }

         }

 

         public static void main(String[] args) {

                   HelloWorldWithReturnNonBlock testClient = new HelloWorldWithReturnNonBlock();

                   testClient.sayHello();

         }

}

注意加粗标红处的代码。

4.3 非阻塞式双工HelloWorldWithReturnDualNonBlock.java

非阻塞式的Web Service客户端代码很简单,在此不做任何擅述,我们就说终极的非阻塞式双工模式的Web Service客户端使用Axis2的API如何实现。

记住以下几个口决:

ü   options.setUseSeparateListener(true);

非阻塞式双工模式,会在客户端也打开一个监听器,而且一直不断的监听着服务器的返回值,该进程一旦被吊用,会一直被挂在客户端这边。

ü   设置webservice客户端模式为双工全开

options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

ü   先寻址,后engageModule

在双工模式下Web Service的客户端需要寻址,即engageModule,这个engageModule需要这样的一个参数:

engageModule(“addressing”)

或者也可写成:

engageModule(Constants.MODULE_ADDRESSING);
这个engageModule就是需要访问你的工程的WEB-INF\modules\目录下的一个叫addressing-1.4.mar的文件。

因此在调用engageModule语句之间有两种方式来调用你的WEB-INF\modules目录下的addressing-1.4.mar文件。

第一种方式:

ConfigurationContext sysContext = ConfigurationContextFactory

                                       .createConfigurationContextFromFileSystem(

                                                         "D:\\wspace\\Axis2Service\\WebContent\\WEB-INF",

                                                         null);

                    sender = new ServiceClient(sysContext, null);

                            sender.engageModule(Constants.MODULE_ADDRESSING);

第二种方式:

sender = new ServiceClient(sysContext, null);

         sender.engageModule(Constants.MODULE_ADDRESSING);

在第二种方式中,不需要为new ServiceClient()指定第一个sysContext参数,但是,你必须把WEB-INF\modules\addressing-1.4.mar指定到你的工程的classpath中去,如下图

要不然运行时会抛出下面这个exception:

org.apache.axis2.AxisFault:Unable to engage module : addressing

下面来看代码,此处的callback我们延用4.2小节中建立的callback接口即可,此处不再重复,直接给出客户端代码:

package org.sky.axis2.helloworld;

 

import org.apache.axiom.om.OMAbstractFactory;

import org.apache.axiom.om.OMElement;

import org.apache.axiom.om.OMFactory;

import org.apache.axiom.om.OMNamespace;

import org.apache.axis2.AxisFault;

import org.apache.axis2.Constants;

import org.apache.axis2.addressing.EndpointReference;

import org.apache.axis2.client.Options;

import org.apache.axis2.client.ServiceClient;

import org.apache.axis2.context.ConfigurationContext;

import org.apache.axis2.context.ConfigurationContextFactory;

 

public class HelloWorldWithReturnDualNonBlock {

private static EndpointReference targetEPR = new EndpointReference(

                    "http://localhost:8080/Axis2Service/services/HelloWorld");

public static boolean finish = false;

 

public void sayHello() {

 

           OMFactory fac = OMAbstractFactory.getOMFactory();

           OMNamespace omNs = fac.createOMNamespace(

                             "http://helloworld.axis2.sky.org", "");

           OMElement method = fac.createOMElement("sayHello", omNs);

           OMElement name = fac.createOMElement("name", omNs);

           name.setText("ymk");

           method.addChild(name);

           method.build();

           Options options = new Options();

           options.setTo(targetEPR);

           options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

           options.setUseSeparateListener(true);

           options.setAction("urn:sayHello");

           ServiceClient sender = null;

 

           HelloWorldNonBlockCB callback = new HelloWorldNonBlockCB();

           try {

                    sender = new ServiceClient();

                    sender.engageModule(Constants.MODULE_ADDRESSING);

                    sender.setOptions(options);

                    sender.sendReceiveNonBlocking(method, callback);

                    synchronized (callback) {

                             try {

                                       callback.wait();

                             } catch (InterruptedException e) {

                                       e.printStackTrace();

                             }

                    }

           } catch (Exception e) {

                    e.printStackTrace();

           } finally {

                    try {

                             sender.cleanup();

                    } catch (Exception e) {

                    }

           }

 

}

 

public static void main(String[] args) {

           HelloWorldWithReturnDualNonBlock testClient = new HelloWorldWithReturnDualNonBlock();

           testClient.sayHello();

}

}

4.4 运行双工异步客户端前的准备工作

将Axis2的安装目录下的conf目录下(如我的是:D:\opensource\axis\axis2-1.4.1-bin\axis2-1.4.1\conf)的axis2.xml拷贝到你的工程的WEB-INF目录下。

并确保这个axis2.xml里有如下语句:

<moduleref="addressing"/>


运行后显示:

Axis2的双工非阻塞式客户端调用成功!完成Axis2编写Web Service的第一天教程。




版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
28103 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
15578 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
20170 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14871 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22248 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23538 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
36366 0
+关注
otteras
在JAVA方面有着14年的开发经验,在多层架构,由其是企业级SOA、异构平台的集成与开发方面拥有相当丰富的工程开发与丰富的带领开发团队的经验与技巧,先后在HP、夸客金融担任过专家、首席架构师,目前为家乐福中国技术总监
86
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载