在前面的隨筆中,我講了我的網(wǎng)站架構(gòu),這樣的架構(gòu)決定了我的網(wǎng)站中必須得用到WebService。比如,在用戶注冊的時(shí)候,用戶數(shù)據(jù)主要是保存在內(nèi)容服務(wù)器中,但是同時(shí)也要將部分?jǐn)?shù)據(jù)提交到索引服務(wù)器中,這時(shí),就可以讓內(nèi)容服務(wù)器訪問索引服務(wù)器提供的WebService來提交數(shù)據(jù);還可以讓內(nèi)容服務(wù)器通過定時(shí)任務(wù),訪問索引服務(wù)器的WebService來提交統(tǒng)計(jì)數(shù)據(jù)。
我的網(wǎng)站使用SpringSide 2.0開發(fā),在SpringSide 2.0中,默認(rèn)使用的是XFire來提供WebService,但是我按照文檔進(jìn)行操作,結(jié)果卻失敗了。于是我向江南白衣請教,白衣推薦我使用CXF的最新版本,于是我到官方網(wǎng)站下載了CXF的最新版,按照示例來了一遍,很快就成功了。由此可見,使用CXF不僅簡單,而且成功率高。因此,我在這里把我的經(jīng)驗(yàn)和大家分享。
第一步,下載CXF的最新版本,下載地址如下圖:
第二步,將CXF中的lib文件夾中的下列jar文件拷貝到我們項(xiàng)目的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
這里有一些包我的項(xiàng)目中本身已經(jīng)帶有了,只不過CXF中提供的版本要更新一些。把這些包拷貝到項(xiàng)目中后,可以刪除項(xiàng)目中的較低的版本,同時(shí)刪除所有和XFire有關(guān)的包。當(dāng)然,不刪除也可以,因?yàn)槲以囘^了,就算項(xiàng)目中存在多個(gè)不同版本的包,也不會(huì)發(fā)生沖突。
當(dāng)然,光拷貝這些包到項(xiàng)目中,還不能保證開發(fā)的順利進(jìn)行,還需要在Eclipse中設(shè)置項(xiàng)目的庫,如下圖:

在這里,我不得不說一下另外一個(gè)問題,那就是啟動(dòng)Tomcat服務(wù)器的時(shí)候,經(jīng)常發(fā)生java.lang.OutOfMemoryError: PermGen space異常,出現(xiàn)這個(gè)異常是什么原因呢?在網(wǎng)上搜到的答案是這樣的:PermGen space的全稱是Permanent Generation space,是指內(nèi)存的永久保存區(qū)域,這塊內(nèi)存主要是被JVM存放Class和Meta信息的,Class在被Loader時(shí)就會(huì)被放到PermGen space中,它和存放類實(shí)例(Instance)的Heap區(qū)域不同,GC(Garbage Collection)不會(huì)在主程序運(yùn)行期對PermGen space進(jìn)行清理,所以如果你的應(yīng)用中有很多CLASS的話,就很可能出現(xiàn)PermGen space錯(cuò)誤,這種錯(cuò)誤常見在web服務(wù)器對JSP進(jìn)行pre compile的時(shí)候。如果你的WEB APP下都用了大量的第三方j(luò)ar, 其大小超過了jvm默認(rèn)的大小(4M)那么就會(huì)產(chǎn)生此錯(cuò)誤信息了。
本來,使用SpringSide 2.0就已經(jīng)包含了許多的第三方包,容易出現(xiàn)這個(gè)問題,現(xiàn)在加入CXF依賴的這些包,就不可避免要出現(xiàn)這個(gè)問題了。這個(gè)問題的解決方法有兩個(gè),其一是不使用SUN的JDK。當(dāng)然,我也懶得去下載一個(gè)別的JDK,因此就選擇了第二個(gè)方法,那就是修改Tomcat的啟動(dòng)文件。
找到SpringSide2.0\misc\servers\tomcat-5.5.17\bin文件夾下的catalina.bat文件,使用記事本打開,找到如下行:
set JAVA_OPTS=
將這一行進(jìn)行修改,加入啟動(dòng)參數(shù),如下:
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>
即可。
第四步,定義一個(gè)提供WebService的接口。在我的項(xiàng)目中,我準(zhǔn)備只提供一個(gè)WebService,即IndexService,這個(gè)服務(wù)中提供多個(gè)方法來分別滿足索引服務(wù)器的各種功能。目前,我還只開發(fā)到了用戶注冊模塊,需要向索引服務(wù)器提交用戶數(shù)據(jù),因此,暫時(shí)提供一個(gè)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);
}
而它的實(shí)現(xiàn)類如下:
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?自動(dòng)生成方法存根
????????return?false;
????}
}
?第五步,在項(xiàng)目的src/resource/spring目錄下,刪除所有和XFire有關(guān)的配置文件,添加一個(gè)cxf-beans.xml文件,其內(nèi)容如下:
<?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>
現(xiàn)在,重新構(gòu)建項(xiàng)目,部署,啟動(dòng)Tomcat,就可以通過訪問
http://www.yumdays.com/service/IndexService?wsdl來測試該WebService是否成功被部署了。如下圖:
第六步,創(chuàng)建客戶端,這一步非常的容易,只需要下面這樣的配置:
<?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>
就可以獲得一個(gè)名稱為client的bean,通過該bean,就可以非常方便的訪問索引服務(wù)器提供的功能。