引入:java
雖然已經用了Apache CXF一段時間了,可是畢竟只是在項目中運用其部分能力,沒有系統的學習,其實CXF還有許多強大的功能,這裏我準備用一些文章系統的介紹Apache CXF的各個特徵。web
例子介紹:spring
演示用Apache CXF對JAX-WS的支持來建立「code first」的web service.apache
實踐tomcat
首先咱們進行架構設計,咱們假設按照傳統慣例,搭建一個maven應用,因此它的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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.charles.cxfstudy</groupId> <artifactId>cxf_jaxws_server</artifactId> <packaging>war</packaging> <name>CXF demo using JAX-WS APIs</name> <description>>CXF demo using JAX-WS APIs</description> <version>1.0.0</version> <properties> <cxf.version>${project.version}</cxf.version> <cxf.release.base>${basedir}/../..</cxf.release.base> <spring.version>3.0.7.RELEASE</spring.version> </properties> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1</version> <configuration> <webXml>src/main/webapp/WEB-INF/web.xml</webXml> </configuration> </plugin> </plugins> <finalName>cxf_jaxws_server</finalName> </build> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>2.7.10</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>2.7.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> </dependencies> </project>
這裏沒什麼技術含量,主要就是添加一些Apache CXF的依賴的jar包的支持,固然了,咱們還考慮到用了spring web(接下來會講),因此也添加了對spring web的支持。session
由於是web應用,因此咱們去編輯web.xml,這裏特別要注意的是,咱們的Apache CXF框架的入口Servlet是CXFServlet,它是一個基於Spring框架的Servlet,它符合攔截和轉發web service的請求,而且調用業務方法進行服務,按照國際慣例,咱們還必須爲其配置url-pattern,從而讓系統知道它會攔截何種請求。(咱們這裏設爲攔截全部 /services/開頭的請求):架構
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>cxf demo for "code first" webservice</display-name> <servlet> <description>Apache CXF Endpoint</description> <servlet-name>cxf-endpoint</servlet-name> <!-- CXFServlet 用於攔截和轉發web service 請求--> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cxf-endpoint</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> </web-app>
下面咱們要寫一個spring 配置文件,叫WEB-INF/cxf-servlet.xml,爲何要寫這個文件呢?咱們來看下Apache CXF的核心Servlet ,CXFServlet的實現:app
public class CXFServlet extends CXFNonSpringServlet implements ApplicationListener<ContextRefreshedEvent> { private static final long serialVersionUID = -5922443981969455305L; private static final String BUS_PARAMETER = "bus"; private boolean busCreated; private XmlWebApplicationContext createdContext; public CXFServlet() { } @Override protected void loadBus(ServletConfig servletConfig) { ApplicationContext wac = WebApplicationContextUtils. getWebApplicationContext(servletConfig.getServletContext()); if (wac instanceof AbstractApplicationContext) { addListener((AbstractApplicationContext)wac); } String configLocation = servletConfig.getInitParameter("config-location"); if (configLocation == null) { try { InputStream is = servletConfig.getServletContext().getResourceAsStream("/WEB-INF/cxf-servlet.xml"); if (is != null && is.available() > 0) { is.close(); configLocation = "/WEB-INF/cxf-servlet.xml"; } } catch (Exception ex) { //ignore } } if (configLocation != null) { wac = createSpringContext(wac, servletConfig, configLocation); }
能夠看出,它會去讀取config-location的配置文件路徑,默認爲/WEB-INF/cxf-servlet.xml,從而建立Spring的上下文。因此咱們能夠想象,這個cxf-servlet.xml(或者其餘名字的配置文件)確定是配置了關於web服務的定義 ,而且將這些服務定義爲spring的bean,以下:框架
<?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" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:server id="cxfJaxwsService" serviceClass="com.charles.cxfstudy.server.services.IGreetingService" address="/greeting"> <jaxws:serviceBean> <bean class="com.charles.cxfstudy.server.services.GreetingServiceImpl" /> </jaxws:serviceBean> </jaxws:server> </beans>
因此咱們這裏就用jaxws的名字空間來聲明提供服務的服務全限定接口,服務的地址和服務的實現全限定類,因此一旦web service部署在spring容器中,就能夠爲外界提供服務了。
接下來就是編碼工做,咱們必須讓咱們的代碼和咱們在cxf-servlet.xml中的配置同樣。因此,咱們定義了IGreetingService的接口:
/** * 這是 web service的接口 */ package com.charles.cxfstudy.server.services; import javax.jws.WebService; import com.charles.cxfstudy.server.vo.Person; /** * @author charles.wang * */ @WebService public interface IGreetingService { /** * 對某個Person發起問候 */ String sayGreetingToPerson(Person person); }
而且在這個接口中提供業務方法。由於咱們的服務是Web服務,因此必須用@WebService註解將其標示。 咱們的接口中能夠出現非java內定類型的類,好比自定義類(這裏的Person類),他們會被JAXB框架(Apache CXF默認支持的綁定框架)來轉爲對應的xml類型定義。
因此咱們的 Person 類就以下:
/** * 這個一個VO,咱們定義了一個Person類型,接下來,咱們會用JAXB框架將其映射爲wsdl文件中的類型定義 */ package com.charles.cxfstudy.server.vo; import javax.xml.bind.annotation.XmlType; /** * 咱們定義一個有姓名(name)和年齡(age)的Person類 * @author charles.wang * */ @XmlType(name="person") public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
能夠看出,這個Person類和通常的Bean沒有區別,惟一區別在於咱們用了註解@XmlType,它會被JAXB識別而且把這個類轉爲對應的xml格式的類型定義。
接下來咱們就來編寫服務實現bean了,根據咱們在cxf-servlet.xml中的定義,咱們開發了GreetingServiceImpl的實現類:
/** * 這是web service的實現類 */ package com.charles.cxfstudy.server.services; import javax.jws.WebService; import com.charles.cxfstudy.server.vo.Person; /** * @author charles.wang * */ @WebService (endpointInterface="com.charles.cxfstudy.server.services.IGreetingService", serviceName="GreetingService") public class GreetingServiceImpl implements IGreetingService { /** * 對某個Person發起問候 */ public String sayGreetingToPerson(Person person) { System.out.println("calling SayGreetingToPerson(Person) method"); String name = person.getName(); int age = person.getAge(); return "Hello ,this is greeting from Charles to: "+name+", and his age is: "+age; } }
從這裏看出,它也和通常具體類沒區別,就是多了一個@WebService註解來表示本身是一個服務實現類。這裏看到其中還有endpointInterface和serviceName屬性,他們都會映射到最終的wsdl文件。
開發完了以後,就足夠了(由於咱們的邏輯太簡單了),咱們maven構建war包,而後部署在tomcat容器上(或者其餘web容器), 就能夠經過URL來測試咱們的應用了。從服務器日誌能夠清楚的看到發佈Web服務的過程:
好比訪問http://localhost:8080/cxf_jaxws_server/services/greeting?wsdl (由於/services請求會被CXFServlet攔截做爲web service請求, /greeting是咱們開發的web service的具體請求,定義在cxf-servlet.xml中)
從上圖能夠看出,這個wsdl文件上部分的 <wsdl:types>中就包含person類型的定義,它是經過JAXB完成的。而下部分則是對咱們的業務方法的定義,其中業務方法中用的入參,返回值類型都有在<wsdl:types>中定義。
對於咱們生成的這個wsdl,咱們能夠很容易用各類工具(好比soapUI)測試其正確性,這裏就不描述了,你們都會。