02 Apache CXF框架介紹
一、關於Apache CXF
Apache CXF = Celtix + XFire,Apache CXF的前身叫Apache Celtixfire,現在正式更名為Apache CXF了,以下簡稱CXF。CXF繼承了Celtix和XFire兩大開源專案的精華,提供了對JAX-WS全面的支援,並且提供了多種Binding、DataBingding、Transport以及各種Format的支援,並且可以根據實際專案的需要,採用程式碼優先(Code First)或者WSDL優先(WSDL First)來輕鬆地實現Web Service的釋出和使用。目前它仍只是Apache的一個孵化專案。
CXF是一個開源的Service框架,CXF幫助您利用Frontend程式設計Api來構建和開發Service,像JAX-WS。這些Web Service可以支援多種協議,比如:SOAP、XML/HTTP、RESTfulHTTP或者CORBA,並且可以在多種傳輸協議上執行,比如:HTTP、JMS或者JBl,CXF大大簡化了Services的建立,同時它集成了XFire傳統,一樣可以無縫和Spring整合。
二、功能特性
CXF包含了大量的功能特性,但主要集中在一下幾個方面:
1、支援Web Service標準:CXF支援多種Web Service標準,包含了SOAP、BasicProfile、WS-Addressing、WS-Policy、WS-ReliableMessaging和WS-Security
2、Frontends:CXF支援多種"Frontend"程式設計模型,CXF實現了JAX-WS API,它也包含一個"Simple Frontend"允許客戶端和EndPoint的建立,而不需要Annotion註解。CXF即支援WSDL優先開發,也支援從Java程式碼優先開發模式。
3、容易使用:CXF設計得更加直觀與容易使用。在大量簡單的API用來快速的程式碼有限的Services,各種Maven的外掛也使整合更加容易,支援JAX-WS API,支援Spring2.0更加簡單化的XML配置方式等等。
4、支援二進位制和遺留協議:CXF的設計是一種可插拔的框架,即可以支援XML,也支援HTTP
三、Apache CXF實現WebService(JAX-WS)
3.1 服務端
1、建立專案
2、新增cxf依賴
<dependencies> <!-- 要進行jaxws服務開發--> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>3.0.1</version> </dependency> <!-- 內建jetty web伺服器--> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>3.0.1</version> </dependency> <!-- 日誌實現--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> <showDeprecation>true</showDeprecation> </configuration> </plugin> </plugins> </pluginManagement> </build>
3、寫服務介面
package com.mars.service;
import javax.jws.WebService;
/**
* 對外發布服務介面
*
* @author: Yizq
* @date: 2020/12/5 16:32
*/
@WebService
public interface HelloService {
/**
*
* @description: 對外發布服務的介面名稱
* @param name
* @return: {@link String}
* @author: Yizq
* @date: 2020/12/5 16:32
*/
String sayHello(String name);
}
4、寫服務介面實現類
package com.mars.service.impl;
import com.mars.service.HelloService;
/**
* 對外發布服務的介面實現類
*
* @author: Yizq
* @date: 2020/12/5 16:34
*/
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return name+",Welcome to WebService";
}
}
5、釋出服務
package com.mars;
import com.mars.service.impl.HelloServiceImpl;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
/**
* 釋出服務
*
* @author: Yizq
* @date: 2020/12/5 16:35
*/
public class Server {
public static void main(String[] args) {
// 釋出服務的工廠
JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
// 設定服務地址
factoryBean.setAddress("http://localhost:8000/ws/hello");
// 設定服務類
factoryBean.setServiceBean(new HelloServiceImpl());
// 釋出服務
factoryBean.create();
System.out.println("釋出服務成功,埠8000");
}
}
執行main方法,在控制檯中會出現輸出文字,則表示釋出成功
log4j:WARN No appenders could be found for logger (org.apache.cxf.common.logging.LogUtils).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
釋出服務成功,埠8000
6、訪問wsdl說明書
3.2 客戶端
1、建立專案。省略
2、新增依賴。可以和服務端依賴保持一致
3、寫服務介面
package com.mars.service;
import javax.jws.WebService;
/**
* 對外發布服務介面
*
* @author: Yizq
* @date: 2020/12/5 16:32
*/
@WebService
public interface HelloService {
/**
*
* @description: 對外發布服務的介面名稱
* @param name
* @return: {@link String}
* @author: Yizq
* @date: 2020/12/5 16:32
*/
String sayHello(String name);
}
4、遠端訪問服務端
package com.mars;
import com.mars.service.HelloService;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
/**
* TODO
*
* @author: Yizq
* @date: 2020/12/5 16:45
*/
public class Client {
public static void main(String[] args) {
// 建立cxf代理工廠
JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
// 設定遠端訪問服務端地址
factoryBean.setAddress("http://localhost:8000/ws/hello");
// 設定介面型別
factoryBean.setServiceClass(HelloService.class);
// 對介面生成代理物件
HelloService helloService = factoryBean.create(HelloService.class);
// 遠端訪問服務端方法
String content = helloService.sayHello("Mars");
System.out.println(content);
}
}
進行執行測試,控制檯中輸出
log4j:WARN No appenders could be found for logger (org.apache.cxf.common.logging.LogUtils).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Mars,Welcome to WebService
3.3 新增日誌攔截器
在服務端中新增log4j.properties檔案
log4j.rootCategory=info,CONSOLE,LOGFILE
log4j.logger.org.apache.axis.enterprise=FATAL,CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
並修改服務端釋出的程式碼
package com.mars;
import com.mars.service.impl.HelloServiceImpl;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
/**
* 釋出服務
*
* @author: Yizq
* @date: 2020/12/5 16:35
*/
public class Server {
public static void main(String[] args) {
// 釋出服務的工廠
JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
// 設定服務地址
factoryBean.setAddress("http://localhost:8000/ws/hello");
// 設定服務類
factoryBean.setServiceBean(new HelloServiceImpl());
// 新增日誌輸入、輸出攔截器,觀察soap請求、響應的內容
factoryBean.getInInterceptors().add(new LoggingInInterceptor());
factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
// 釋出服務
factoryBean.create();
System.out.println("釋出服務成功,埠8000");
}
}
在客戶端呼叫過程中,控制檯會輸出如下內容
2020-12-05 16:56:12,443 0 [ main] INFO y.ReflectionServiceFactoryBean - Creating Service {http://impl.service.mars.com/}HelloServiceImplService from class com.mars.service.HelloService
2020-12-05 16:56:12,726 283 [ main] INFO apache.cxf.endpoint.ServerImpl - Setting the server's publish address to be http://localhost:8000/ws/hello
2020-12-05 16:56:12,742 299 [ main] INFO rg.eclipse.jetty.server.Server - jetty-8.1.15.v20140411
2020-12-05 16:56:12,881 438 [ main] INFO jetty.server.AbstractConnector - Started SelectChannelConnector@localhost:8000
釋出服務成功,埠8000
2020-12-05 16:56:21,512 9069 [tp1565740893-17] INFO loServiceImplPort.HelloService - Inbound Message
----------------------------
ID: 1
Address: http://localhost:8000/ws/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[192], content-type=[text/xml; charset=UTF-8], Host=[localhost:8000], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 3.0.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHello xmlns:ns2="http://service.mars.com/"><arg0>Mars</arg0></ns2:sayHello></soap:Body></soap:Envelope>
--------------------------------------
2020-12-05 16:56:21,599 9156 [tp1565740893-17] INFO loServiceImplPort.HelloService - Outbound Message
---------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHelloResponse xmlns:ns2="http://service.mars.com/"><return>Mars,Welcome to WebService</return></ns2:sayHelloResponse></soap:Body></soap:Envelope>
--------------------------------------
以上幾個引數需要解釋的是:
- ID:表示當前服務被呼叫的次數,以1開始,依次+1
- Address:伺服器釋出的地址
- Encoding:編碼規則
- Http-Method:請求的方式
- Content-Type:上下文的內容格式
- Headers:服務請求的內容
- Response-Code:請求的結果,200為成功
- Plyload:響應的內容