一、關于CXF的曆史
網上可以很輕松的搜到相關的CXF曆史。我就簡單的說一下:CXF是一個實作Web Service的架構,由Celtix 和XFire合并而成,目前是Apache的頂級項目。
webservice領域比較有名的架構目前主要還有Axis2。相比較而言,CXF更新速度較快,而Axis2已經好久沒更新了。
二、使用 CXF内置的 Jetty釋出 WS服務端
學習先從官網開始: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
1.第一步就配置 Maven 依賴
下面是我的pom.xml。每個人可能不完全一樣,但是cxf-rt-frontend-jaxws和jetty依賴不能少,也可直接複制官網提供的pom.xml,那個比較全。
[html] view plain copy print ?
- <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>
<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是包含源檔案的)
2.編寫服務接口和接口實作
[java] view plain copy print ?
- package com.alibaba.cxf;
- import javax.jws.WebService;
- @WebService
- public interface HelloWorld {
- String sayHi(String name);
- }
package com.alibaba.cxf;
import javax.jws.WebService;
/**
* @author tfj
* 2015年1月7日
* WS 接口
*/
@WebService
public interface HelloWorld {
String sayHi(String name);
}
[java] view plain copy print ?
- package com.alibaba.cxf.impl;
- import javax.jws.WebService;
- import com.alibaba.cxf.HelloWorld;
- @WebService
- public class HelloWorldImpl implements HelloWorld{
- @Override
- public String sayHi(String name) {
- return "hello " + 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 自動為我們取預設值即可。
3.釋出webService服務(這裡以JAX-WS方式釋出)
[java] view plain copy print ?
- 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;
- 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");
- }
- }
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。
三、在 Web 容器中使用 Spring + CXF 釋出 WS服務端
官網上這部分給的例子比較舊,是以這裡我參考的是http://my.oschina.net/huangyong/blog/286439。
1.同樣的,在maven中加入spring的依賴
[html] view plain copy print ?
- <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>
<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>
2.編寫服務接口和接口實作。
這裡由于要和spring整合,是以加入component注解,便于Spring IOC容器掃描。
[java] view plain copy print ?
- package com.alibaba.cxf.impl;
- import javax.jws.WebService;
- import org.springframework.stereotype.Component;
- import com.alibaba.cxf.HelloWorld;
- @Component
- @WebService
- public class HelloWorldImpl implements HelloWorld{
- @Override
- public String sayHi(String name) {
- return "hello " + name;
- }
- }
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;
}
}
3.配置 web.xml。
[html] view plain copy print ?
- <?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"?>
<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>
4.配置 Spring.xml。
[html] view plain copy print ?
- <?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>
<?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的配置檔案分離
5.配置 Spring-cxf.xml。
[html] view plain copy print ?
- <?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>
<?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>
6.釋出webservice
将應用部署到 Tomcat 中,在浏覽器中輸入以下位址可進入 CXF 控制台:
http://127.0.0.1:8080/CXF/

四、建構WS用戶端
上面兩個方法主要講的是建構WS服務端,即通過 CXF對外釋出了 WS,下面要做的事情就是用 WS用戶端來通路和調用WS了。
1.靜态代理用戶端
這種方法,需要告訴通路者你的url、服務接口類(Helloworld)、服務接口名,顯然太多了。一般而言,通路者隻需要知道url和調用方法就行了,是以有了下面的方法
[java] view plain copy print ?
- 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 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);
}
2.動态代理用戶端
[html] view plain copy print ?
- 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();
- // }
- }
/**
* 通用動态代理用戶端
*/
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();
// }
}
3.基于spring的用戶端
[java] view plain copy print ?
- 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);
- }
/**
* 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