最近,公司的GlassFish移植項目基本告以段落,由于之前的代碼嚴重依賴于Weblogic,給移植工作帶來了很大的難度,很多實現(xiàn)方式在GlassFish中根本就沒有對應(yīng)的替代品。在經(jīng)歷了幾個月的移植之后,竟讓我對Weblogic開始產(chǎn)生好感了,作為一款商用的Application Server,Weblogic確實非常成熟,非常強大,提供了很多特性,以幫助提高程序的運行效率,但是太笨重了,訪問Admin Console極慢;GlassFish作為一款開源的Application Server,非常適合開發(fā)者使用,速度很快,并且嚴格遵照J2EE的標準,以達到平臺獨立的特性,但是確實簡陋了點,只提供了最標準的實現(xiàn),并且還存在一些明顯的BUG,社區(qū)不夠活躍,文檔、資源都很少,可能是現(xiàn)在SUN處于動亂期,連商業(yè)Support都很難聯(lián)系到。下面是我在做移植工作時,隨筆記下來的一些小經(jīng)驗,讓其他的同學(xué)們少受一些折磨,少踩一些坑。
1、EJB
Client與weblogic.jar沖突
若使用EJB Client訪問GlassFish中的EJB,需將appserv-rt.jar、appserv-ext.jar、appserv-deployment-client.jar和javaee.jar加入到classpath中。若classpath中存在weblogic.jar,則可能會遇到錯誤:
java.lang.NoSuchMethodError:
org.omg.CosTransactions.OTSPolicy.value()S
將weblogic.jar從classpath中移除即可。
2、Transaction使用
使用Spring的JtaTransactionManager需要配置兩個屬性:JtaTransactionManager 和userTransactionName。對于GlassFish,JtaTransactionManager 為 java:appserver/TransactionManager , userTransactionName 為 java:comp/UserTransaction。只有Bean管理的SessionBean和MDB允許使用UserTransaction,Entity Bean只允許使用Container管理的transaction。如果Container管理的SessionBean或MDB使用了UserTransaction,則會出現(xiàn)錯誤: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,需要有一個獨立的XADataSource,和數(shù)據(jù)表EJB__TIMER__TBL,建表語句可在<server_path>/lib/install/databases中找到。對于developer模式,GlassFish默認使用內(nèi)置的__TimerPool,不需要你手工創(chuàng)建datasource和表;對于cluster模式,Admin Server會默認使用__TimerPool,Cluster則需要單獨配置。如果讓Admin Server和Cluster同時使用手工創(chuàng)建的datasource,則可能導(dǎo)致Cluster配置中的timer datasource在server重啟后丟失,Timer
Service會出現(xiàn)異常,這應(yīng)該是GlassFish的BUG,目前的解決方案就是Admin Server用默認的Timer配置,Cluster用另外的配置。
5、ClassLoader優(yōu)先加載
在weblogic中,可以通過配置prefer-application-packages來優(yōu)先加載application中的類,在GlassFish中則沒有對應(yīng)的方式來控制加載順序,一個典型的場景就是:項目中采用CXF作為webservice的實現(xiàn),但GlassFish中默認使用了Metro的實現(xiàn),由于Metro的jar包比application加載的早,就會導(dǎo)致CXF依賴的類庫沒有正常加載,而是使用了Metro的JAX-WS的實現(xiàn)。
6、CMP配置中的數(shù)據(jù)庫表名區(qū)分大小寫
CMP在GlassFish中需要配置sun-cmp-mappings.xml,該XML中的table-name是區(qū)分大小寫的,Oracle中的表名默認是大寫的,如果這里的table-name寫成小寫,就會報找不到表的錯誤,可以通過添加一個*.dbschema文件,對表名進行適配,以減少切換數(shù)據(jù)庫時的修改操作。
7、GlassFish的部署結(jié)果不可靠
在使用asadmin部署EAR時,如果沒有遇到極其嚴重的錯誤,部署一般都會返回成功,但這個結(jié)果并不可靠,你需要關(guān)注server.log,如果這里出現(xiàn)了錯誤,應(yīng)用程序則可能沒有真正部署成功,在運行時就會出現(xiàn)錯誤,所以要確保你的程序部署時,server.log中沒有錯誤信息。
8、TLD路徑
根據(jù)JSP2.1規(guī)范,tld文件不能存放在/WEB-INF/classes或者/WEB-INF/lib目錄中,特別不能放在/WEB-INF/tags目錄或子目錄中,否則會出現(xiàn)錯誤:
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”
在Tomcat和Weblogic中不會出現(xiàn)該問題,GlassFish則嚴格遵照規(guī)范,可將tld文件放置在/WEB-INF/tld目錄。
9、注冊servlet listener
在web.xml中注冊servlet的listener時,在<listener>中添加多個<listener-class>不會報錯,但是只有最后一個<listener-class>生效,因此,要注冊多個listener,需要添加多個<listener>。
10、
Pass-by-reference
Weblogic中的call-by-reference能夠極大的提高本地接口調(diào)用的效率,在GlassFish中也有相應(yīng)的替代,就是pass-by-reference,可以在sun-ejb-jar.xml中對某個EJB進行配置,也可以在sun-application.xml中配置,這樣就可以對整個application中的EJB生效。
11、HTTP錯誤消息體
當HTTP的ErrorCode大于400,并且相應(yīng)的消息體是空時,GlassFish會自動在返回的Response中添加錯誤信息,對于使用HttpClient操作時,就可能和我們期望的Response不同,該問題的解決辦法:在往Response中寫入內(nèi)容后,調(diào)用response.getOutputStream().flush()
或 response.flushBuffer();或者在web.xml中設(shè)置ErrorcCde對應(yīng)的ErrorPage,ErrorPage可以是一個空內(nèi)容的頁面。
12、ServletRequest中inputStream的使用
InputStream有一個markSupported屬性,如果該屬性為true,則支持mark和reset,可以多次讀取該流,反之則只能讀取一次該輸入流。一種情形就是:如果在Filter中讀取了該InputStream,則不能在Servlet中再次讀取。ServletRequest中的InputStream在不同的Server中有不同的實現(xiàn),在Weblogic中markSupported就設(shè)為了true,在GlassFish中則為false。