一、war包中的文件的讀取
在開發J2EE(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 interpreted
as relative to the current context root.
This method allows the servlet container
to make a resource available to servlets
from 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(最大使用內存)即可解決。當然,這兒的內存容量都是指物理內存,不能超出你的機器的物理內存的總容量。