1. 程式人生 > >CXF開發WebService整合Spring

CXF開發WebService整合Spring

開發環境jdk1.7  CXF版本3.1.17

如果使用3.1以上的高版本CXF框架,則需要jdk1.8的支援。

專案採用簡單的web專案整合了spring框架,專案啟動則對外發布服務,所需要的jar包,點選連結下載

該jar包就是根據maven依賴得到的最精簡的jar包

如果是maven專案請參考一下依賴資訊

 <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.1.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.1.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.1.17</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
</dependencies>

專案截圖

釋出服務

web.xml

增加了CXF框架的Servlet,新增訪問地址對映,訪問路徑需要包含/servcies/才可以訪問到WebService服務

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	version="2.5"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    
	       http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<display-name>cxf</display-name>

	<servlet>
		<description>Apache CXF Endpoint</description>
		<display-name>cxf</display-name>
		<servlet-name>cxf</servlet-name>
		<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>cxf</servlet-name>
		<url-pattern>/services/*</url-pattern>
	</servlet-mapping>
	
	<session-config>
		<session-timeout>60</session-timeout>
	</session-config>
</web-app>

java類

demo.spring.service包下的Demo,代表服務類。必須在類上加 @WebService註解,才可以釋出該類

import javax.jws.WebService;

@WebService
public class Demo {

	public String sayDemo(String s){
		return s;
	}
}

cxf-servlet.xml

這個檔案是釋出服務的配置檔案,id 可以隨意起名,implementor 代表要釋出服務的類在專案中的全限定類名,按著ctrl+滑鼠左鍵可以跳轉到該類上,代表全限定類名沒有寫錯。address 代表要釋出服務地址的最後一位以/demo結尾

<?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.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd ">
	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<jaxws:endpoint id="demo" implementor="demo.spring.service.Demo"
		address="/demo" />
	
</beans>

如果訪問頁面不報錯,則代表釋出服務成功。

客戶端呼叫

拿到根據服務地址產生的介面檔案

在磁碟任意位置新建一個資料夾,在資料夾內按shift+滑鼠右鍵,在此處開啟命令視窗。

即可解析生成java介面檔案。根據地址的 portType型別,拿到同名的介面檔案,放到專案中。

首先改包名,然後刪除報錯的地方即可。

demo.spring.interfaces  包下的Demo 即為介面產生的檔案。

client-beans.xml

這個檔案代表客戶端呼叫的配置檔案。

第一個bean       id 隨便起,獲取類要用到。class代表產生介面的類在專案中的全限定類名,factory-bean

代表 引用名。在下面的bean id中引用。factory-method="create" 固定值。

第二個bean    id 為 factory-bean的值。class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" 固定值。

         <property name="serviceClass" value="demo.spring.interfaces.Demo" />
        <property name="address" value="http://localhost:8080/cxf_web/services/demo" />

紅色部分為變動的。第一個value 代表介面的類在專案中的全限定類名。第二個value 代表該類釋出地址的WebServcie

格式為:http://部署地址ip:釋出服務埠/專案名/services/釋出服務地址配置的最後一位(address)。

<?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.xsd 
	http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
	
	<bean id="demo" class="demo.spring.interfaces.Demo" factory-bean="demoFactory"
		factory-method="create" />
	<bean id="demoFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
		<property name="serviceClass" value="demo.spring.interfaces.Demo" />
		<property name="address" value="http://localhost:8080/cxf_web/services/demo" />
	</bean>

</beans>

呼叫服務

demo.spring.client 包下的Client  代表呼叫服務類。

import org.springframework.context.support.ClassPathXmlApplicationContext;

import demo.spring.interfaces.Demo;

public class Client {

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

		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
				new String[] { "client-beans.xml" });

		Demo bean = (Demo) context.getBean("demo");
		String sayDemo = bean.sayDemo("abc");
		System.out.println(sayDemo);
		context.close();
		System.exit(0);
	}
}

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                new String[] { "client-beans.xml" });

代表spring載入配置檔案,產生物件。紅色的就是專案中配置檔名稱。

context.getBean("demo");    demo就是客戶端配置檔案的bean id。強制轉換為 自動生成的Demo檔案,不要用自己寫的。

在呼叫之前先啟動服務,可以訪問到webservice服務。再用客戶端呼叫,如果能夠輸出輸入的值,代表客戶端呼叫成功。

到這裡釋出服務,呼叫服務就完成了。運用cxf框架優勢在於客戶端只需要服務端產生的介面檔案就可以完成呼叫。

思考

一般的專案都是web專案,啟動專案即可釋出服務。本案例中釋出服務就是這樣。

但是,客戶端呼叫是main方法啟動,不友好。應該客戶端啟動就可以拿到spring建立的物件,直接使用物件呼叫方法。

解決方案

1.採用單例模式,讓配置檔案只加載一次

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SingletonContext {
	private SingletonContext() {
	} // 私有建構函式

	private volatile static ClassPathXmlApplicationContext Context = null; // 單例物件

	public static ClassPathXmlApplicationContext getContext() {
		if (Context == null) {
			synchronized (SingletonContext.class) { // 同步鎖
				if (Context == null) { // 雙重檢測機制
					Context = new ClassPathXmlApplicationContext(new String[] { "client-beans.xml" });
				}
			}
		}
		return Context;
	}
}

2.. 專案啟動讓spring載入客戶端配置的檔案,產生物件。然後在專案中@AutoWired 注入使用。

注意web.xml配置  spring監聽器,指定監聽客戶端配置檔案

client-beans.xmll  配置spring 包掃描,掃描指定介面檔案。注意新增spring context名稱空間約束

專案中引用

@Autowired

private Demo demo;