技术开发 频道

运用Spring DM和CXF来实现WebService 的动态发布

验证当前的工作正确 

 到目前为止,CXFBundle的基本工作已经完成,现在需要写一个Web Service的应用来验证当前的工作是正确的;

  在设计Web Service应用Bundle的时候需要考虑以下几个事情:

  1、 每个WebService应用的实现应该做为一个独立的Bundle运行;

  2、 按照WebService的推荐设计方式,一般都是先定义好WSDL文件,然后根据这个文件定义的Contract来实现服务端和客户端;CXF提供了相关的工具将WSDl编译成桩代码。这个桩代码包括Web Service接口的JAVA定义,以及由WSDL引用的XML Schema生成的关键数据对象。这些生成代码应该做为一个独立的DummyBundle来运行;

  3、 这个DummyBundle要做为CXFBundle 的Required Bundle;

  这里的WSDL文件使用的是CXF下载包中带的例子中的一个,读者可以在CXF的Sample目录中找到这个hello_world.wsdl文件;

  在Eclipse环境下建立一个新的Bundle,给名字为WsDummyBundle,这个Bundle不需要提供Active类!使用CXF提供的Wsdl2Java工具对这个WSDL进行编译,将编译生成的代码全部做为这个Bundle的内部实现:

  然后在MANIFEST.MF文件中的Runtime面板中导出这两个包:

  Export-Package: org.apache.hello_world_soap_http,

  org.apache.hello_world_soap_http.types

  至此,构建WsDummyBundle的工作就算完成;

  接下来创建WebService应用的实现Bundle:这个Bundle将使用Spring DM的能力来获取CXFBundle发布的Web Service注册接口服务(WSRegister)来发布,所以首先要定义一个HelloWorldBean类,用于完成Web Service的注册:

  public class HelloWorldBean {

  private WSRegister register;

  public void setRegister(WSRegister register){

  this.register = register;

  }

  public WSRegister getRegister(){

  return this.register;

  }

  public void start(){

  GreeterImpl impl = new GreeterImpl();

  register.Regiser(Greeter.class, impl, "/Greeter");

  }

  }

  注意SpringDM将把WSRegister(OSGI服务)实例注射给register变量,在start方法中,实现最终的注册过程。

  这里注意一下调用Regiser函数时的Address参数,这里只需要给出一个相对路径就可以了,最终WebService将被发布在http://localhost/services/Greeter这个URL上。

  由于这里使用了WSRegister这个接口定义,所以在MANIFEST.MF文件中要导入CXFWrapper.interfaces;

  定义类MyGreeterImp来实现WSDL定义的接口:

  @javax.jws.WebService(name = "Greeter",

  serviceName = "SOAPService",

  portName = "SoapPort",

  targetNamespace = "http://apache.org/hello_world_soap_http",

  wsdlLocation = "http://localhost/internal/hello_world.wsdl",

  endpointInterface = "org.apache.hello_world_soap_http.Greeter")

  public class MyGreeterImpl extends Greeter{

  ...

  }

  由于这里使用了Greeter接口和其他WSDL桩代码定义的类,所以在MANIFEST.MF文件中要导入

  org.apache.hello_world_soap_http,

  org.apache.hello_world_soap_http.types

  这两个包;

  这里还需要注意,如果wsdlLocation给出,处理要稍微复杂些:hello_world.wsdl文件必须能够通过这个wsdlLocation指定的URL:http://localhost/internal/hello_world.wsdl访问到。这个URL可以根据具体情况来配置!

  为了使WSDL能够被正确的访问到,需要再次使用OSGI的Http服务,这次暴露出来的不是Servlet而是WSDL文件:

  private class WSDLServiceTracker extends ServiceTracker{

  public Object addingService(ServiceReference reference) {

  HttpService httpService = (HttpService) context.getService(reference);

  try {

  httpService.registerResources("/internal/hello_world.wsdl", "/hello_world.wsdl", null);

  } catch (Exception e) {

  ...

  然后要在HelloWorldBean中启动这个ServiceTracker:

  public void start(){

  httpServiceTracker = new WSDLServiceTracker(context);

  httpServiceTracker.open();

  GreeterImpl impl = new GreeterImpl();

  register.Regiser(Greeter.class, impl, "/Greeter");

  }

  如果wsdlLocation没有给出,CXF将通过反射机制来获取JAXWS2.1运行时所必须的信息。

  最后要定义SpringDM要求的配置文件,同样有两个,都要放置在META-INF/spring目录下,一个是标准的Spring Bean定义文件:

  

  init-method="start" >
  另一个是SpringDM的OSGI服务配置文件:
    注意这里的osgi:reference的id和上面property的ref属性值应该相同。
  至此这个Bundle的实现完成。

  最后要对CXFBundle做一些收尾的工作,由于Bundle和Bundle之间使用了不同的类加载器,所以必须使用导入导出的方式让不同的Bundle实现类的共享。CXF的运行时需要能够看到任何被注册服务所必须的桩类信息,所以CXFBundle也必须要导入WsDummyBundle导出的所有包。但是从工程的角度来说WsDummyBundle导出什么库不是事先确定的,需要根据具体的WebSevice来确定,因此每次发布新的WebService的时候,都需要修改CXFBundle得到MANIFEST.MF文件,这是非常麻烦的一件事情。

  如果将WsDummyBundle做为CXFBundle的Required Bundle,那么WsDummyBundle将被和CXFBundle相同的类加载器加载,WsDummyBundle包含的所有类对CXF都缺省可见,这样的话发布新的服务就非常的简单:

  1、 将桩代码封装到WsDummyBundle中,导出必要的包;

  2、 实现你的WebService Bundle;

  3、 运行就可以了,不需要对CXFBundle做任何改动!

  基于上述的讨论,因此要在CXFBundle的MANIFEST.MF的Dependencies页面加入

  Require-Bundle: WSDummyBundle

  运行整个系统,使用ss命令查看Bundle的状态:

  ss

  Framework is launched.

  id State Bundle

  0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900

  10 ACTIVE org.apache.commons.logging_1.0.4.v20080605-1930

  19 ACTIVE org.eclipse.osgi.services_3.1.200.v20071203

  29 ACTIVE org.springframework.bundle.spring.core_2.5.1

  30 ACTIVE org.springframework.bundle.osgi.io_1.0.3

  31 ACTIVE org.springframework.bundle.osgi.extender_1.0.3

  32 ACTIVE org.eclipse.equinox.http.servlet_1.0.100.v20080427-0830

  33 ACTIVE org.eclipse.equinox.http.jetty_1.1.0.v20080425

  34 ACTIVE org.springframework.bundle.osgi.core_1.0.3

  35 ACTIVE org.springframework.bundle.spring.context_2.5.1

  36 ACTIVE org.springframework.bundle.spring.beans_2.5.1

  37 ACTIVE javax.servlet_2.4.0.v200806031604

  42 ACTIVE org.mortbay.jetty_5.1.14.v200806031611

  43 ACTIVE org.springframework.osgi.aopalliance.osgi_1.0.0.SNAPSHOT

  46 ACTIVE WSDummyBundle_1.0.0

  47 ACTIVE org.springframework.bundle.spring.aop_2.5.1

  49 ACTIVE CXFWrapper_1.0.0

  50 ACTIVE HelloWorldBundle_1.0.0

  通过IE浏览器访问地址http://localhost/services,将展示如下信息,这个信息是CXFNonSpringServlet提供的:

  点击WSDL连接,就可以看到完整的关于这个WebService的WSDL信息;

0
相关文章