一、war包中的文件的读取
在开发j2ee web应用时,在开发阶段通常采用目录的部署方式,而在正式运行时通常把web应用打包为单个的.war文件进行方便地部署。也就是在你的应用目录(比如weblogic的defaultwebapp)下,执行下面的命令:
jar cf0 mywebapp.war ** |
这样,要部署到正式系统时就非常方便,只需要把这个.war文件拷贝到weblogic的applications目录或tomcat的webapps目录下即可自动进行部署。tomcat会对部署的.war应用包进行自动监控、解包,所以不会出现下面提到的问题。
而weblogic并不会自动解包.war,所以如果在你的应用中,需要读取原来应用中的配置文件或其它资源文件时,就会发现,在解包部署时,正常运行的程序,在weblogic中打包部署时,运行却出错,会报告找不到该文件。例如下面的应用:
[pre] |--defaultwebapp |--index.jsp |--.....jsp |--web-inf |-- web.xml |-- log4j.properties |-- classes ......[/pre] |
其中使用到了log4j作为日志输出工具,log4j的配置文件log4j.propertes放在defaultwebapp/web-inf目录下。log4j通过一个自动加载的servlet进行初始化,初始化代码如下:
servletcontext context = getservletcontext(); org.apache.log4j.propertyconfigurator.configure(context.getrealpath("/")+ "/web-inf/log4j.properties"); |
其中,context.getrealpath("/")得到当前web应用的真实根目录,比如,如果你的weblogic安装在d:/bea下,在windows下context.getrealpath("/")通常会返回:
d:/bea/wlserver6.1/config/mydomain/applications/defaultwebapp |
在unix下类似:
/bea/wlserver6.1/config/mydomain /applications/defaultwebapp |
这样,和
"/ web-inf /log4j.properties" |
拼接后,就得到了log4j.properties文件的真实路径,log4j通过文件io读取这个配置文件,完成初始化。
现在一切正常!测试通过后,将defaultwebapp下的所有文件打为一个.war包,进行部署时,发现系统报告找不到“d:/bea/wlserver6.1/null/ web-inf /log4j.properties”文件!如果你的应用中还需要读取其它已经被打包到war包中的文件,都会报告找不到文件。并且,系统并不会到d:/bea/wlserver6.1/config/mydomain/applications/defaultwebapp目录下寻找,而会到d:/bea/wlserver6.1/null下寻找。这是因为context.getrealpath("/")返回了null。
查看servletcontext的api文档,原来,对一个打包的应用来说,是没有realpath的概念的,调用getrealpath只会简单地返回null。其实,也很好理解,一个文件被打包入了.war文件,就不存在目录结构了(虽然包中仍然存在目录结构,但这不等同于文件系统中的目录结构)。
所以,对war包中的资源是无法得到realpath的。这样也就无从通过文件io进行读取了。那么,如何读取war包中的资源呢?答案是使用servletcontext.getresourceasstream(string)方法。对于org.apache.log4j.propertyconfigurator,有如下几种配置方法:
static void configure(properties properties); static void configure(string configfilename); static void configure(url configurl); |
既然,现在不能得到war包中的log4j的配置文件,那么可以通过读入inputstream,构造一个properties,通过configure(properties properties)方法同样可以完成配置。示例代码如下:
inputstream is = getservletcontext(). getresourceasstream("/web-inf/log4j.properties"); properties props = new properties(); try{ props.load(is); }catch (ioexception e){ system.err.println("load log4j configuration failed"); } propertyconfigurator.configure(props); |
那么,现在对于war应用可以成功运行,但如果现在不通过war部署,直接通过目录结构部署应用会不会又出现找不到资源的错误呢?请来看看servletcontext.getresourceasstream的api文档,
returns a url to the resource that is mapped to a specified path. the path must begin with a "/" and is interpretedas relative to the current context root. this method allows the servlet container to make a resource available to servletsfrom any source. resources can be located on a local or remote file system,in a database, or in a .war file. |
可见,通过getresourceasstream可以获取包括本地文件系统、远程文件系统、war包等资源。不会出现上面担心的问题。
结论:在开发j2ee web应用时,如果需要读取本应用中的文件,尽量使用servletcontext.getresourceasstream进行,而不要使用文件io。
二、ant使用中的outofmemoryerror解决
在开发大型项目时,类文件通常有数千个之多,这时都需要采用一些make工具来辅助开发。有时需要编译的类太多,使用ant编译时,会出现outofmemoryerror的错误,使编译进程中断。这时,通常通过先移出部分文件,分批编译。但java编译过程的自动依赖编译,通常很难确定究竟应该先移出哪些文件、后移出哪些文件伤透脑筋。下面为你提供一个简便的方法:转到你的ant的安装目录,在bin子目录中找到ant.bat,使用文字编辑器打开,修改:runant处的允许命令,添加如下参数:
:runant"%_javacmd%" -xms128m -xmx512m -classpath …… |
如果你安装了jike,使用jike编译器,则需要修改:runantwithjikes处的运行命令,同上。
结论:java虚拟机默认分配64m内存,如果你的应用比较大,超出64m内存,java虚拟机就会抛出outofmemoryerror,并停止运行。不管是什么应用(web应用、application等),只需要修改你的机器上的运行java命令,在java xxx命令中添加-xms(最小使用内存)、-xmx(最大使用内存)即可解决。当然,这儿的内存容量都是指物理内存,不能超出你的机器的物理内存的总容量。
闽公网安备 35060202000074号