欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于CXF的WebServie技术应用

程序员文章站 2024-01-17 12:55:34
...

基于CXFWebServie技术应用

1   概述

面向服务的体系结构(service-oriented architectureSOA)是一种思想,它将应用程序的不同功能单元通过中立的契约(独立于硬件平台、操作系统、编程语言)联系起来,使各个形式的功能单元更好的集成。WebServiceSOA思想的一种较好实现方式,它和普通的web程序一样(如JSPASP)采用HTTP协议进行通讯,但是它只用POST方式通讯,它的数据是基于XML格式的,采用SOAPSimple Object Access Protocol)协议。SOAP协议实际上就是基于XML编码规范的文本协议,它是WebService特有的应用协议。

1.1      WebService体系架构


基于CXF的WebServie技术应用
            
    
    博客分类: java基础 webservice cxf java 
 

 

1.2      CXF说明

JAVA平台上对WebService支持的成熟框架很多,如CXFAXIS1&2XFire等,本文使用CXF

Apache CXF = Celtix + XFire,前身叫 Apache CeltiXfire,已经正式更名为 Apache CXF 了,以下简称为 CXFCXF 继承了 Celtix XFire 两大开源项目的精华,是Apache基金会组织下的一个*项目,简化了WebService服务端的创建过程。

CXF实现了JAX-WS2.0规范,并通过了JAX-WS2.0 TCK

CXF可以和Spring无缝集成;

CXF支持多种传输协议(HTTP JMS Corba等);

CXF支持多种Binding数据格式(SOAPXMLJSON等);

CXF 支持多种DataBinding数据类型(JAXB Aegis)

CXF基于Interceptor的架构,使得整个框架非常易于扩展。本次我主要讨论CXFHTTP/SOAP模式下的处理机制。

CXF的下载地址为:http://cxf.apache.org/download.html,下载后解压压缩包,从lib中至少要拿出如下jar到应用:

cxf-2.2.5.jar

antlr-2.7.7.jar

commons-codec-1.3.jar

commons-collections-3.2.1.jar

commons-lang-2.4.jar 

commons-logging-1.1.1.jar

commons-pool-1.5.2.jar 

geronimo-annotation_1.0_spec-1.1.1.jar

geronimo-jaxws_2.1_spec-1.0.jar 

geronimo-ws-metadata_2.0_spec-1.1.2.jar

jaxb-api-2.1.jar

xalan-2.7.1.jar

wsdl4j-1.6.2.jar 

XmlSchema-1.4.5.jar

2      构建服务端

2.1      Servlet构建的简单服务端

1)         定义webservice接口和实现类

publicinterface IHelloWorld {

             public String sayHello(String name);

}

publicclass HelloWorldImpl implements IHelloWorld {

            public String sayHello(String name) {

                 return"Hello " + name + ".";

            }

}

 

2)         定义webservice

publicclass HelloWorldServlet extends CXFNonSpringServlet {

privatestaticfinallongserialVersionUID = 1L;

@Override

protectedvoid loadBus(ServletConfig sc) {

    super.loadBus(sc);

     Bus bus = getBus();

     //如果我们要发布多个WebService,仅仅需要修改WebService的接口定义、发布地址、实现类,然后不断重复下面的代码即可

     ServerFactoryBean factory = new ServerFactoryBean();

     factory.setBus(bus);

     factory.setServiceClass(IHelloWorld.class);

     factory.setAddress("/HelloWorld");

     factory.setServiceBean(new HelloWorldImpl());

     factory.create();

}

}

         首先CXF的内部上下文对象Bus,然后我再使用CXF提供的ServerFactoryBean工具类把自己写的一个普通的JavaBean发布成WebService

ServerFactoryBean需要以下参数:

1) Bus。也就是上面我们所得到的Bus对象。

2) WebService的接口定义,也就是指自己的WebService实现了哪个Java Interface

3) WebService的发布地址,也就是访问WebServiceURL地址。

4) WebService的实现类。

web.xml中配置HelloWorldServlet

<servlet>    

<servlet-name> HelloWorldServlet </servlet-name>

<servlet-class> HelloWorldServlet</servlet-class>

<load-on-startup>1</load-on-startup>

       </servlet> 

<servlet-mapping>

<servlet-name>HelloWorldServlet</servlet-name>

<url-pattern>/services/*</url-pattern>

</servlet-mapping>

启动服务器,访问http://127.0.0.1:8080/CXFDemo/services/?wsdl,可以看到服务列表,http://127.0.0.1:8080/CXFDemo/services/HelloWorld?wsdl就是我们的服务地址。

2.2      java注解的简单服务端

webservice实现类加上注解

@WebService

public class HelloWorldImpl implements IHelloWorld {

public String sayHello(@WebParam(name = "text") String name) {

           return "Hello " + name + ".";

}

}

构建服务端

public class SimpleServer {

public SimpleServer() {

           System.out.println("Starting Server");

           IHelloWorld helloService = new HelloWorldImpl();

           String address = "http://localhost:9000/helloWorld";

           Endpoint.publish(address, helloService);

}

public static void main(String[] args) throws InterruptedException {

          

           //System.out.println(System.getProperty("java.endorsed.dirs"));

           new SimpleServer();

           System.out.println("Server ready...");

           Thread.sleep(6000000);

           System.out.println("Server exiting");

           System.exit(0);

}

}

           运行应用程序,访问http://localhost:9000/helloWorld?wsdl,已经发布成功,可以看到服务没有在web服务器中发布,这是因为CXF内置了Jetty应用服务器,可以直接在Jetty上发布。

2.3      结合spring构建web服务

1)         声明实体

@XmlType(name = "User")

@XmlAccessorType(XmlAccessType.FIELD)

publicclass User implements Serializable {

    privatestaticfinallongserialVersionUID = 1L;

    private String username;

    private String password;

 

    public String getUsername() {

        returnusername;

    }

    publicvoid setUsername(String username) {

        this.username = username;

    }

    public String getPassword() {

        returnpassword;

    }

    publicvoid setPassword(String password) {

        this.password = password;

    }

}

2)         声明接口

import javax.jws.WebService;

import javax.jws.soap.SOAPBinding;

import javax.jws.soap.SOAPBinding.Style;

 

@WebService

@SOAPBinding(style = Style.RPC)

publicinterface IHelloService {

  User saveUser(User user);

  User getMaxLongNameUser(User u1, User u2);

}

 

3)         声明实现

import javax.jws.WebService;

import javax.jws.soap.SOAPBinding;

import javax.jws.soap.SOAPBinding.Style;

import org.apache.log4j.Logger;

 

@WebService

@SOAPBinding(style = Style.RPC)

publicclass HelloServiceImpl implements IHelloService {

    privatestatic Logger log = Logger.getRootLogger();

    public User saveUser(User user) {

        log.debug("saveUser is called!");

        return user;

    }

    public User getMaxLongNameUser(User u1, User u2) {

        log.debug("getMaxLongNameUser is called!");

        return u1;

    }

}

4)         spring配置

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jaxws="http://cxf.apache.org/jaxws"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd

    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd

    http://cxf.apache.org/jaxws

    http://cxf.apache.org/schemas/jaxws.xsd">

 

    <!-- 还需要引入以下3个关于CXF的资源文件,这三个文件在cxf.jar -->

    <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="inInter" class="org.apache.cxf.interceptor.LoggingInInterceptor" />

    <bean id="outInter" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />

    <jaxws:endpoint id="userManager" address="/UserManager"

        implementorClass="com.pgw.test.webservice.IHelloService">

        <jaxws:implementor>

            <bean id="userServiceImpl" class="com.pgw.test.webservice.HelloServiceImpl">

            </bean>

        </jaxws:implementor>

        <!-- 加入拦截器 -->

        <jaxws:inInterceptors>

            <ref bean="inInter" />

            <ref bean="outInter" />

        </jaxws:inInterceptors>

    </jaxws:endpoint>

</beans>

5)         web.xml配置

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>/WEB-INF/config/*.xml</param-value>

    </context-param>

    <listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

    <listener>

        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>

    </listener>

    <servlet>

        <servlet-name>CXFService</servlet-name>

        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>

    </servlet>

    <servlet-mapping>

        <servlet-name>CXFService</servlet-name>

        <url-pattern>/*</url-pattern>

    </servlet-mapping>

完成上述操作后发布web程序,在浏览器中输入

http://127.0.0.1:8080/CXFDemo/UserManager?wsdl查看服务。另外在部署中可能会遇到JAXB 2.0 API is being loaded from the bootstrap classloader这个错误,这是因为cxf2.2.5需要jaxb-api-2.1.jar支持,而低版本的jdk1.6默认的是jaxb-api-2.0.jar,解决办法如下:

重新构建一个相同类型的项目(不同的项目类型,输出的结果不一样),在项目中打印输出System.getProperty("java.endorsed.dirs"),如果文件系统中不存在输出的目录则创建,把jaxb-api-2.1.jar放置到该目录下,问题解决。

3      构建客户端

3.1      WSDL2Java构建客户端

WSDL2Java位于cxfbin目录下,可以根据wsdl生成java客户端代码。在命令行中输入 WSDL2JAVA –help 可以获取该指令的帮助。

如下所示:

wsdl2java -frontend jaxws21

-p com.ailk.demo.webservice.client.wsdl2Java

-d D:\workspace\olcom5\CXFDemo\src\ http://localhost:8080/CXFDemo/services/HelloWorld?wsdl

 

客户端生成后进行调用:

publicclass ClientMain {

 

publicstaticvoid main(String[] args) {

     IHelloWorld helloWorld = new IHelloWorld();

     IHelloWorldPortType client = helloWorld.getIHelloWorldPort();

     String resultStr = client.sayHello("test");

     System.out.println("HelloWorld webService response :" + resultStr);

}

}

3.2      JAX-WS Proxy构建客户端

import java.net.MalformedURLException;

import java.net.URL;

import javax.xml.namespace.QName;

import javax.xml.ws.Service;

import com.ailk.demo.service.IHelloWorld;

 

publicclass ClientMain {

publicstaticvoid main(String[] args) throws MalformedURLException {

     URL wsdlURL = new URL("http://localhost:9000/helloWorld?wsdl");

     QName SERVICE_NAME = new QName("http://impl.service.demo.ailk.com/", "HelloWorldImplService");

     QName PORT_NAME = new QName("http://impl.service.demo.ailk.com/", "HelloWorldImplPort");

     Service service = Service.create(wsdlURL, SERVICE_NAME);

     IHelloWorld client = service.getPort(PORT_NAME, IHelloWorld.class);

     String result = client.sayHello("test");

     System.out.println("HelloWorld webService response :" + result);

}

}

3.3      JaxWsProxyFactoryBean构建客户端

JaxWsProxyFactoryBean简化了Proxy

publicclass ClientMain {

publicstaticvoid main(String[] args) {

     JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

     factory.setServiceClass(IHelloWorld.class);

     factory.setAddress("http://localhost:9000/helloWorld?wsdl");

     IHelloWorld client = (IHelloWorld) factory.create();

     String result = client.sayHello("test");

     System.out.println("HelloWorld webService response :" + result);

}

}

3.4      JaxWsClientProxy动态客户端

DynamicClientFactory factory = DynamicClientFactory.newInstance();

     Client client = factory.

createClient("http://localhost:8080/CXFDemo/services/HelloWorld?wsdl");

     try {

         Object[] objs = client.invoke("sayHello",

new Object[] { "test" });

         System.out.println("HelloWorld webService response :" + objs[0]);

     } catch (Exception e) {

         e.printStackTrace();

}

3.5      JaxWsDynamicClientFactory动态客户端

 

import org.apache.cxf.endpoint.Client;

import org.apache.cxf.endpoint.ConduitSelector;

import org.apache.cxf.endpoint.Endpoint;

import org.apache.cxf.endpoint.UpfrontConduitSelector;

import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;

import org.apache.cxf.transport.http.HTTPConduit;

import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;

 

publicclass ClientMain {

 

publicstaticvoid main(String[] args) throws Exception {

     JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();

     Client client = dcf.createClient("http://localhost:8080/CXFDemo/services/HelloWorld?wsdl");

     // sayHello 为接口中定义的方法名称 test为传递的参数返回一个Object数组

     Object[] objects = client.invoke("sayHello", "test");

     // 输出调用结果

     System.out.println("HelloWorld webService response :" + objects[0]);

     // 动态设置Address

     Endpoint ep = client.getEndpoint();

ep.getEndpointInfo().setAddress("http://localhost:8080/CXFDemo/services/HelloWorld");

     ConduitSelector cs = new UpfrontConduitSelector();

     cs.setEndpoint(ep);

     client.setConduitSelector(cs);

 

     // 设置连接超时时间、相应超时时间

     HTTPConduit http = (HTTPConduit) client.getConduit();

     HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();

     httpClientPolicy.setConnectionTimeout(60000);

     httpClientPolicy.setAllowChunking(false);

     httpClientPolicy.setReceiveTimeout(600000);

     http.setClient(httpClientPolicy);

 

     objects = client.invoke("sayHello", "test");

     // 输出调用结果

     System.out.println("HelloWorld webService response :" + objects[0]);

}

}

客户端创建的过程中,生产服务下所有的方法类、参数类、返回值类,耗时比较惊人,建议在实际应用中预先初始化。

 

在实际的项目应用中,有这样的场景,提供的服务是相同的,但是服务地址会随着业务的需求动态的变化,就需要我们动态的设置服务地址。

  • 基于CXF的WebServie技术应用
            
    
    博客分类: java基础 webservice cxf java 
  • 大小: 8.2 KB