webservice领域比较有名的框架目前主要还有Axis2。相比较而言,CXF更新速度较快,而Axis2已经好久没更新了。
学习先从官网开始:http://cxf.apache.org/,左侧有个user's guide,点击进入。
官网上说,CXF目前主要有三种服务方式:SOAP、REST-ful、CORBA。
这篇博文用的是第一种服务方式,根据官方指导可知,CXF官网推荐我们使用maven构建CXF的应用,那么我们就使用maven。不会用maven的同学可以参考http://blog.csdn.net/tonytfjing/article/details/39006087
下面是我的pom.xml。每個人可能不完全一样,但是cxf-rt-frontend-jaxws和jetty依赖不能少,也可直接复制官网提供的pom.xml,那个比较全。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>CXF</groupId> <artifactId>CXF</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>CXF</name> <description /> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <cxf.version>3.0.3</cxf.version> </properties> <build> <sourceDirectory>src</sourceDirectory> <resources> <resource> <directory>src</directory> <excludes> <exclude>**/*.java</exclude> </excludes> </resource> </resources> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.2</version> <configuration> <warSourceDirectory>${basedir}/WebRoot</warSourceDirectory> <version>3.0</version> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> <dependencies> <!-- CXF --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency> </dependencies> </project>
不想使用 Maven的童鞋,那么就需要从以下地址下载 CXF 的相关 jar 包,并将其放入应用中。
http://cxf.apache.org/download.html (binary distribution是jar包,而source distribution是包含源文件的)
package com.alibaba.cxf; import javax.jws.WebService; /** * @author tfj * 2015年1月7日 * WS 接口 */ @WebService public interface HelloWorld { String sayHi(String name); }
package com.alibaba.cxf.impl; import javax.jws.WebService; import com.alibaba.cxf.HelloWorld; /** * @author tfj * 2015年1月7日 * WS 接口实现 */ @WebService public class HelloWorldImpl implements HelloWorld{ @Override public String sayHi(String name) { return "hello " + name; } }
这里简化了实现类上的 WebService 注解的配置,让 CXF 自动为我们取默认值即可。
package com.alibaba.cxf; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; import com.alibaba.cxf.impl.HelloWorldImpl; /** * @author tfj * 2015年1月7日 * 发布服务 */ public class JaxWsServer { public static void main(String[] args) { HelloWorldImpl implementor = new HelloWorldImpl(); JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean(); // 除了http://localhost部分其他部分可以随便写,但格式不能乱 http://IP:PORT/NAME factory.setAddress("http://localhost:8080/ws/hello"); factory.setServiceClass(HelloWorld.class);//可省,但不建议,因为可能会有些小问题 factory.setServiceBean(implementor); // //LoggingInInterceptor和LoggingOutInterceptor是日志拦截器,用于输入和输出时显示日志 factory.getInInterceptors().add(new LoggingInInterceptor()); factory.getOutInterceptors().add(new LoggingOutInterceptor()); factory.create(); System.out.println("ws is published"); } }
运行该类之后,就相当于发布了webservice,我们可以在浏览器中输入http://localhost:8080/ws/hello?wsdl来查看WSDL。
看到这里,第一个简单的demo出来了,但是这种方式显然不适用于生产环境,通常情况下我们还是需要依靠于 Tomcat 与 Spring。
官网上这部分给的例子比较旧,所以这里我参考的是http://my.oschina.net/huangyong/blog/286439。
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.1.4.RELEASE</version> </dependency>
package com.alibaba.cxf.impl; import javax.jws.WebService; import org.springframework.stereotype.Component; import com.alibaba.cxf.HelloWorld; /** * @author tfj * 2015年1月7日 * WS 接口实现 */ @Component @WebService public class HelloWorldImpl implements HelloWorld{ @Override public String sayHi(String name) { return "hello " + name; } }
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <!-- Spring --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- CXF --> <servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.alibaba.cxf" /> <import resource="spring-cxf.xml" /> </beans>
告诉spring扫描路径(根据自己的包名写),并将cxf的配置文件分离
<?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:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:endpoint id="helloWorld" implementor="com.alibaba.cxf.impl.HelloWorldImpl" address="/spring/hello"/> </beans>
将应用部署到 Tomcat 中,在浏览器中输入以下地址可进入 CXF 控制台:
http://127.0.0.1:8080/CXF/
上面两个方法主要讲的是构建WS服务端,即通过 CXF对外发布了 WS,下面要做的事情就是用 WS客户端来访问和调用WS了。
这种方法,需要告诉访问者你的url、服务接口类(Helloworld)、服务接口名,显然太多了。一般而言,访问者只需要知道url和调用方法就行了,所以有了下面的方法
/** * 静态代理客户端 */ public static void JaxWsClient(String address) { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setAddress(address); factory.setServiceClass(HelloWorld.class); HelloWorld helloService = factory.create(HelloWorld.class); String result = helloService.sayHi("JaxWsClient"); System.out.println(result); }
/** * 通用动态代理客户端 */ public static void DynamicClient(String address) { //CXF发布用的是业务类(HelloWorldImpl.java),那么默认的命名空间就会是业务类所在包(路径), //而对外界暴露的则是接口类(HelloWorld.java),那么对于客户端(第三方)调用访问时,需要按照接口类所在包(路径)进行命名空间的定义 QName opName = new QName("http://cxf.alibaba.com/", "sayHi"); // 指定到接口类所在包 address = address+"?wsdl"; DynamicClientFactory factory = DynamicClientFactory.newInstance(); Client client = factory.createClient(address); try { Object[] results = client.invoke(opName, "DynamicClient"); System.out.println(results[0]); } catch (Exception e) { e.printStackTrace(); } //如果接口和实现在同一路径下,就使用下面的代码. // address = address+"?wsdl"; // DynamicClientFactory factory = DynamicClientFactory.newInstance(); // Client client = factory.createClient(address); // try { // Object[] results = client.invoke("sayHi", "DynamicClient"); // System.out.println(results[0]); // } catch (Exception e) { // e.printStackTrace(); // } }
/** * spring客户端 */ public static void SpringClient() { context = new ClassPathXmlApplicationContext("spring-client.xml"); HelloWorld helloService = context.getBean("helloWorld", HelloWorld.class); String result = helloService.sayHi("SpringClient"); System.out.println(result); }
到此CXF的基础知识已经讲了,剩下的就是扩展了,比如流行的RESTFUL啊、Security啊等等。
代码下载地址:http://download.csdn.net/detail/tonytfjing/8341849