最近,公司的GlassFish移植項(xiàng)目基本告以段落,由于之前的代碼嚴(yán)重依賴于Weblogic,給移植工作帶來了很大的難度,很多實(shí)現(xiàn)方式在GlassFish中根本就沒有對(duì)應(yīng)的替代品。在經(jīng)歷了幾個(gè)月的移植之后,竟讓我對(duì)Weblogic開始產(chǎn)生好感了,作為一款商用的Application Server,Weblogic確實(shí)非常成熟,非常強(qiáng)大,提供了很多特性,以幫助提高程序的運(yùn)行效率,但是太笨重了,訪問Admin Console極慢;GlassFish作為一款開源的Application Server,非常適合開發(fā)者使用,速度很快,并且嚴(yán)格遵照J(rèn)2EE的標(biāo)準(zhǔn),以達(dá)到平臺(tái)獨(dú)立的特性,但是確實(shí)簡陋了點(diǎn),只提供了最標(biāo)準(zhǔn)的實(shí)現(xiàn),并且還存在一些明顯的BUG,社區(qū)不夠活躍,文檔、資源都很少,可能是現(xiàn)在SUN處于動(dòng)亂期,連商業(yè)Support都很難聯(lián)系到。下面是我在做移植工作時(shí),隨筆記下來的一些小經(jīng)驗(yàn),讓其他的同學(xué)們少受一些折磨,少踩一些坑。

      1、EJB Clientweblogic.jar沖突

若使用EJB Client訪問GlassFish中的EJB,需將appserv-rt.jarappserv-ext.jar、appserv-deployment-client.jarjavaee.jar加入到classpath中。若classpath中存在weblogic.jar,則可能會(huì)遇到錯(cuò)誤:
java.lang.NoSuchMethodError: org.omg.CosTransactions.OTSPolicy.value()S
weblogic.jarclasspath中移除即可。

      2、Transaction使用

使用SpringJtaTransactionManager需要配置兩個(gè)屬性:JtaTransactionManager userTransactionName。對(duì)于GlassFish,JtaTransactionManager java:appserver/TransactionManager , userTransactionName java:comp/UserTransaction。只有Bean管理的SessionBeanMDB允許使用UserTransactionEntity Bean只允許使用Container管理的transaction。如果Container管理的SessionBeanMDB使用了UserTransaction,則會(huì)出現(xiàn)錯(cuò)誤:Lookup of java:comp/UserTransaction not allowed for Container managed Transaction beans。

      3、HTTP Thread count

使用asadmin修改HTTP thread count后,從Admin Console上訪問,Admin Server的配置可生效,但Cluster不生效,檢查domain.xml已改變,通過asadmin查詢也已生效,應(yīng)該是GlassFish頁面展示的BUG。

      4、EJB Timer的使用

GlassFish中使用EJB Timer,需要有一個(gè)獨(dú)立的XADataSource,和數(shù)據(jù)表EJB__TIMER__TBL,建表語句可在<server_path>/lib/install/databases中找到。對(duì)于developer模式,GlassFish默認(rèn)使用內(nèi)置的__TimerPool,不需要你手工創(chuàng)建datasource和表;對(duì)于cluster模式,Admin Server會(huì)默認(rèn)使用__TimerPoolCluster則需要單獨(dú)配置。如果讓Admin ServerCluster同時(shí)使用手工創(chuàng)建的datasource,則可能導(dǎo)致Cluster配置中的timer datasourceserver重啟后丟失,Timer Service會(huì)出現(xiàn)異常,這應(yīng)該是GlassFishBUG,目前的解決方案就是Admin Server用默認(rèn)的Timer配置,Cluster用另外的配置。

      5、ClassLoader優(yōu)先加載

weblogic中,可以通過配置prefer-application-packages來優(yōu)先加載application中的類,在GlassFish中則沒有對(duì)應(yīng)的方式來控制加載順序,一個(gè)典型的場(chǎng)景就是:項(xiàng)目中采用CXF作為webservice的實(shí)現(xiàn),但GlassFish中默認(rèn)使用了Metro的實(shí)現(xiàn),由于Metrojar包比application加載的早,就會(huì)導(dǎo)致CXF依賴的類庫沒有正常加載,而是使用了MetroJAX-WS的實(shí)現(xiàn)。

      6、CMP配置中的數(shù)據(jù)庫表名區(qū)分大小寫

CMPGlassFish中需要配置sun-cmp-mappings.xml,該XML中的table-name是區(qū)分大小寫的,Oracle中的表名默認(rèn)是大寫的,如果這里的table-name寫成小寫,就會(huì)報(bào)找不到表的錯(cuò)誤,可以通過添加一個(gè)*.dbschema文件,對(duì)表名進(jìn)行適配,以減少切換數(shù)據(jù)庫時(shí)的修改操作。

      7、GlassFish的部署結(jié)果不可靠

在使用asadmin部署EAR時(shí),如果沒有遇到極其嚴(yán)重的錯(cuò)誤,部署一般都會(huì)返回成功,但這個(gè)結(jié)果并不可靠,你需要關(guān)注server.log,如果這里出現(xiàn)了錯(cuò)誤,應(yīng)用程序則可能沒有真正部署成功,在運(yùn)行時(shí)就會(huì)出現(xiàn)錯(cuò)誤,所以要確保你的程序部署時(shí),server.log中沒有錯(cuò)誤信息。

       8、TLD路徑

 根據(jù)JSP2.1規(guī)范,tld文件不能存放在/WEB-INF/classes或者/WEB-INF/lib目錄中,特別不能放在/WEB-INF/tags目錄或子目錄中,否則會(huì)出現(xiàn)錯(cuò)誤:
 exception: org.apache.jasper.JasperException: PWC6180: Unable to initialize TldLocationsCache
 root cause: org.apache.jasper.JasperException: PWC6336: Illegal TLD path /WEB-INF/tags/fn.tld, must not start with “/WEB-INF/tags”
 在
TomcatWeblogic中不會(huì)出現(xiàn)該問題,GlassFish則嚴(yán)格遵照規(guī)范,可將tld文件放置在/WEB-INF/tld目錄。

     9、注冊(cè)servlet listener

web.xml中注冊(cè)servletlistener時(shí),在<listener>中添加多個(gè)<listener-class>不會(huì)報(bào)錯(cuò),但是只有最后一個(gè)<listener-class>生效,因此,要注冊(cè)多個(gè)listener,需要添加多個(gè)<listener>。

      10、 Pass-by-reference

Weblogic中的call-by-reference能夠極大的提高本地接口調(diào)用的效率,在GlassFish中也有相應(yīng)的替代,就是pass-by-reference,可以在sun-ejb-jar.xml中對(duì)某個(gè)EJB進(jìn)行配置,也可以在sun-application.xml中配置,這樣就可以對(duì)整個(gè)application中的EJB生效。

      11、HTTP錯(cuò)誤消息體

當(dāng)HTTPErrorCode大于400,并且相應(yīng)的消息體是空時(shí),GlassFish會(huì)自動(dòng)在返回的Response中添加錯(cuò)誤信息,對(duì)于使用HttpClient操作時(shí),就可能和我們期望的Response不同,該問題的解決辦法:在往Response中寫入內(nèi)容后,調(diào)用response.getOutputStream().flush() response.flushBuffer();或者在web.xml中設(shè)置ErrorcCde對(duì)應(yīng)的ErrorPage,ErrorPage可以是一個(gè)空內(nèi)容的頁面。

      12、ServletRequestinputStream的使用

InputStream有一個(gè)markSupported屬性,如果該屬性為true,則支持markreset,可以多次讀取該流,反之則只能讀取一次該輸入流。一種情形就是:如果在Filter中讀取了該InputStream,則不能在Servlet中再次讀取。ServletRequest中的InputStream在不同的Server中有不同的實(shí)現(xiàn),在WeblogicmarkSupported就設(shè)為了true,在GlassFish中則為false