在前面的隨筆中,我講了我的網站架構,這樣的架構決定了我的網站中必須得用到 WebService。比如,在用戶注冊的時候,用戶數據主要是保存在內容服務器中,但是同時也 要將部分數據提交到索引服務器中,這時,就可以讓內容服務器訪問索引服務器提供的 WebService來提交數據;還可以讓內容服務器通過定時任務,訪問索引服務器的WebService 來提交統計數據。
我的網站使用SpringSide 2.0開發,在SpringSide 2.0中,默認使用的是XFire來提供 WebService,但是我按照文檔進行操作,結果卻失敗了。於是我向江南白衣請教,白衣推薦 我使用CXF的最新版本,於是我到官方網站下載了CXF的最新版,按照示例來了一遍,很快就 成功了。由此可見,使用CXF不僅簡單,而且成功率高。因此,我在這裡把我的經驗和大家分 享。
第一步,下載CXF的最新版本,下載地址如下圖:
第二步,將CXF中的lib文件夾中的下列jar文件拷貝到我們項目的webapp/WEB-INF/lib目 錄下:
commons-logging-1.1.jar
geronimo-activation_1.1_spec-1.0-M1.jar (or Sun's Activation jar)
geronimo-annotation_1.0_spec-1.1.jar (JSR 250)
geronimo-javamail_1.4_spec-1.0-M1.jar (or Sun's JavaMail jar)
geronimo-servlet_2.5_spec-1.1-M1.jar (or Sun's Servlet jar)
geronimo-ws-metadata_2.0_spec-1.1.1.jar (JSR 181)
jaxb-api-2.0.jar
jaxb-impl-2.0.5.jar
jaxws-api-2.0.jar
neethi-2.0.jar
saaj-api-1.3.jar
saaj-impl-1.3.jar
stax-api-1.0.1.jar
wsdl4j-1.6.1.jar
wstx-asl-3.2.1.jar
XmlSchema-1.2.jar
xml-resolver-1.2.jar
cxf-2.0-incubator.jar
這裡有一些包我的項目中本身已經帶有了,只不過CXF中提供的版本要更新一些。把這些 包拷貝到項目中後,可以刪除項目中的較低的版本,同時刪除所有和XFire有關的包。當然, 不刪除也可以,因為我試過了,就算項目中存在多個不同版本的包,也不會發生沖突。
當然,光拷貝這些包到項目中,還不能保證開發的順利進行,還需要在Eclipse中設置項 目的庫,如下圖:
在這裡,我不得不說一下另外一個問題,那就是啟動Tomcat服務器的時候,經常發生 java.lang.OutOfMemoryError: PermGen space異常,出現這個異常是什麼原因呢?在網上搜 到的答案是這樣的:PermGen space的全稱是Permanent Generation space,是指內存的永久 保存區域,這塊內存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到 PermGen space中,它和存放類實例(Instance)的Heap區域不同,GC(Garbage Collection)不會 在主程序運行期對PermGen space進行清理,所以如果你的應用中有很多CLASS的話,就很可能 出現PermGen space錯誤,這種錯誤常見在web服務器對JSP進行pre compile的時候。如果你的 WEB APP下都用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那麼就會產生此錯誤信 息了。
本來,使用SpringSide 2.0就已經包含了許多的第三方包,容易出現這個問題,現在加入 CXF依賴的這些包,就不可避免要出現這個問題了。這個問題的解決方法有兩個,其一是不使 用SUN的JDK。當然,我也懶得去下載一個別的JDK,因此就選擇了第二個方法,那就是修改 Tomcat的啟動文件。
找到SpringSide2.0\misc\servers\tomcat-5.5.17\bin文件夾下的catalina.bat文件,使用記 事本打開,找到如下行:
set JAVA_OPTS=
將這一行進行修改,加入啟動參數,如下:
set JAVA_OPTS=%JAVA_OPTS% -Xms512m -Xmx1024m -XX:MaxNewSize=512m -XX:MaxPermSize=512m -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties":noJuli
解決了以上這些問題,就可以正式使用CXF了。
第三步,修改webapp/WEB-INF/web.xml文件,將以前的
<servlet>
修改為:
<servlet-name>xfire</servlet-name>
<servlet-class>org.codehaus.xfire.spring.XFireSpringServlet</servlet- class>
</servlet>
<servlet-mapping>
<servlet-name>xfire</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping><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>/service/*</url-pattern>
</servlet-mapping>
即可。
第四步,定義一個提供WebService的接口。在我的項目中,我准備只提供一個WebService ,即IndexService,這個服務中提供多個方法來分別滿足索引服務器的各種功能。目前,我 還只開發到了用戶注冊模塊,需要向索引服務器提交用戶數據,因此,暫時提供一個addUser 方法作為示例,如下:
package com.yumdays.service;
import javax.jws.WebService;
import com.yumdays.model.SUser;
@WebService
public interface IndexService {
public boolean addUser(SUser user,String adminName,String adminPassword);
}
而它的實現類如下:
package com.yumdays.service;
import com.yumdays.model.SUser;
import javax.jws.WebService;
@WebService(endpointInterface = "com.yumdays.service.IndexService")
public class IndexServiceImpl implements IndexService {
public boolean addUser(SUser user, String adminName, String adminPassword) {
// TODO 自動生成方法存根
return false;
}
}
第五步,在項目的src/resource/spring目錄下,刪除所有和XFire有關的配置文件,添加 一個cxf-beans.xml文件,其內容如下:
<?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-2.0.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-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="indexServiceBean" class="com.yumdays.service.IndexServiceImpl" />
<jaxws:endpoint id="indexService" implementor="#indexServiceBean" address="/IndexService" />
</beans>
現在,重新構建項目,部署,啟動Tomcat,就可以通過訪問 http://www.yumdays.com/service/IndexService?wsdl來測試該WebService是否成功被部署 了。如下圖:
第六步,創建客戶端,這一步非常的容易,只需要下面這樣的配置:
<?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-2.0.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-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="client" class="com.yumdays.service.IndexService" factory- bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.yumdays.service.IndexService"/>
<property name="address" value="http://www.yumdays.com/service/IndexService"/>
</bean>
</beans>
就可以獲得一個名稱為client的bean,通過該bean,就可以非常方便的訪問索引服務器提 供的功能。