最近,公司的GlassFish移植项目基本告以段落,由于之前的代码严重依赖于Weblogic,给移植工作带来了很大的难度,很多实现方式在GlassFish中根本就没有对应的替代品。在经历了几个月的移植之后,竟让我对Weblogic开始产生好感了,作为一款商用的Application Server,Weblogic确实非常成熟,非常强大,提供了很多特性,以帮助提高程序的运行效率,但是太笨重了,访问Admin Console极慢;GlassFish作为一款开源的Application Server,非常适合开发者使用,速度很快,并且严格遵照J2EE的标准,以达到平台独立的特性,但是确实简陋了点,只提供了最标准的实现,并且还存在一些明显的BUG,社区不够活跃,文档、资源都很少,可能是现在SUN处于动乱期,连商业Support都很难联系到。下面是我在做移植工作时,随笔记下来的一些小经验,让其他的同学们少受一些折磨,少踩一些坑。

      1、EJB Clientweblogic.jar冲突

若使用EJB Client访问GlassFish中的EJB,需将appserv-rt.jarappserv-ext.jarappserv-deployment-client.jarjavaee.jar加入到classpath中。若classpath中存在weblogic.jar,则可能会遇到错误:
java.lang.NoSuchMethodError: org.omg.CosTransactions.OTSPolicy.value()S
weblogic.jarclasspath中移除即可。

      2、Transaction使用

使用SpringJtaTransactionManager需要配置两个属性:JtaTransactionManager userTransactionName。对于GlassFishJtaTransactionManager java:appserver/TransactionManager userTransactionName java:comp/UserTransaction。只有Bean管理的SessionBeanMDB允许使用UserTransactionEntity Bean只允许使用Container管理的transaction。如果Container管理的SessionBeanMDB使用了UserTransaction,则会出现错误: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查询也已生效,应该是GlassFish页面展示的BUG

      4、EJB Timer的使用

GlassFish中使用EJB Timer,需要有一个独立的XADataSource,和数据表EJB__TIMER__TBL,建表语句可在<server_path>/lib/install/databases中找到。对于developer模式,GlassFish默认使用内置的__TimerPool,不需要你手工创建datasource和表;对于cluster模式,Admin Server会默认使用__TimerPoolCluster则需要单独配置。如果让Admin ServerCluster同时使用手工创建的datasource,则可能导致Cluster配置中的timer datasourceserver重启后丢失,Timer Service会出现异常,这应该是GlassFishBUG,目前的解决方案就是Admin Server用默认的Timer配置,Cluster用另外的配置。

      5、ClassLoader优先加载

weblogic中,可以通过配置prefer-application-packages来优先加载application中的类,在GlassFish中则没有对应的方式来控制加载顺序,一个典型的场景就是:项目中采用CXF作为webservice的实现,但GlassFish中默认使用了Metro的实现,由于Metrojar包比application加载的早,就会导致CXF依赖的类库没有正常加载,而是使用了MetroJAX-WS的实现。

      6、CMP配置中的数据库表名区分大小写

CMPGlassFish中需要配置sun-cmp-mappings.xml,该XML中的table-name是区分大小写的,Oracle中的表名默认是大写的,如果这里的table-name写成小写,就会报找不到表的错误,可以通过添加一个*.dbschema文件,对表名进行适配,以减少切换数据库时的修改操作。

      7、GlassFish的部署结果不可靠

在使用asadmin部署EAR时,如果没有遇到极其严重的错误,部署一般都会返回成功,但这个结果并不可靠,你需要关注server.log,如果这里出现了错误,应用程序则可能没有真正部署成功,在运行时就会出现错误,所以要确保你的程序部署时,server.log中没有错误信息。

       8、TLD路径

 根据JSP2.1规范,tld文件不能存放在/WEB-INF/classes或者/WEB-INF/lib目录中,特别不能放在/WEB-INF/tags目录或子目录中,否则会出现错误:
 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中不会出现该问题,GlassFish则严格遵照规范,可将tld文件放置在/WEB-INF/tld目录。

     9、注册servlet listener

web.xml中注册servletlistener时,在<listener>中添加多个<listener-class>不会报错,但是只有最后一个<listener-class>生效,因此,要注册多个listener,需要添加多个<listener>

      10、 Pass-by-reference

Weblogic中的call-by-reference能够极大的提高本地接口调用的效率,在GlassFish中也有相应的替代,就是pass-by-reference,可以在sun-ejb-jar.xml中对某个EJB进行配置,也可以在sun-application.xml中配置,这样就可以对整个application中的EJB生效。

      11、HTTP错误消息体

HTTPErrorCode大于400,并且相应的消息体是空时,GlassFish会自动在返回的Response中添加错误信息,对于使用HttpClient操作时,就可能和我们期望的Response不同,该问题的解决办法:在往Response中写入内容后,调用response.getOutputStream().flush() response.flushBuffer();或者在web.xml中设置ErrorcCde对应的ErrorPageErrorPage可以是一个空内容的页面。

      12、ServletRequestinputStream的使用

InputStream有一个markSupported属性,如果该属性为true,则支持markreset,可以多次读取该流,反之则只能读取一次该输入流。一种情形就是:如果在Filter中读取了该InputStream,则不能在Servlet中再次读取。ServletRequest中的InputStream在不同的Server中有不同的实现,在WeblogicmarkSupported就设为了true,在GlassFish中则为false