今天看到一篇博文。如下:
經常開發java web應用程序的朋友一定對有對程序打包,維護的經驗,我們提高軟件的維護性一般可以從分離易變和不變的內容,重構軟件的結構來實現,重構包括對代碼級別的,也包括對應用程序目錄文件的重構,以下我就簡單談談我的一次經歷。
我們一個系統是java web應用程序,不過該系統所有的class文件、jsp、js、CSS、image文件和系統動態上傳的doc、xls、image、wmv等文件放在同一個工程目錄中。具體目錄結構如下:
應用程序配置的上下文根目錄是/myappmyapp/WEB-INF/myapp/admin/myapp/images/myapp/style/myapp/files/myapp/videos/......
1、存在的問題 實際上,files、videos文件夾,會在系統運行中隨著用戶上傳發布新內容經常更新變化,而其他的部分都是在系統需求變更發布版本時才變化,這2種變化不同,前者是系統正常使用的結果,后者是系統變更的結果,根據變化與不變化分開的原則,我們希望把這2類文件夾分開存放。 由于我們發布web應用程序包(myapp.war)需要把應用程序上下文根目錄myapp中的所有文件夾都包括進來,所以必須把經常變化的files和videos文件夾移出去。
2、解決方法探索 我們知道,servlet中有兩種轉向的方法,一個是request.getRequestDispatcher(requestPath).forward(request,
response),它不改變url地址,直接轉發請求到一個jsp頁面,一個是resonse.sendRedirect(urlPath),它改版url地址,跳轉到另外一個請求。 不過其兩者都沒法訪問servlet所在web應用程序上下文(myapp)之外的目錄,而我們myapp內的全部文件夾都需要打包成myapp.war,這樣就有個矛盾。 另外的方法,還有通過java.io.File使用流的方式讀一個文件,然后再使用servlet的response的out對象寫出來傳送到頁面,這樣的方法可以訪問到該web容器(如tomcat)所在操作系統的用戶根目錄(如windows的D:/或linux的/usr*等等),這樣我們就可以把files等文件夾移動到myapp之外。比如tomcat的應用程序上下文根目錄是/usr/tomcat/webapps/,我們讓files不在myapp中,而是放到/usr/upload/files中,這樣我們打包myapp.war的時候,就只裝載版本變化的最新版程序,用戶上傳文件都不變仍然放在files中,訪問時使用File()來進行。如: File f = new File("/usr/upload/files/2010/3/15/010001.doc")
使用FileInputStream來讀這個文件,然后使用response中的outstream來寫這個文件流到頁面。 這其中存在的問題是讀入的文件需要占用JVM的heap空間,如果文件有500MB大,那么一般的默認JVM heap空間都是不夠的,需要在啟動JVM的時候設置參數,使之足夠容納這個文件,當然文件的讀寫都要使用JVM來調度,顯然效率會比較低,比直接讀取要慢很多。
3、方法的改進 有沒有辦法,既能讓files文件夾在myapp之外,又不用File類來讀文件數據流呢? 在linux中可以使用目錄的快捷方式來解決,實際上就是文件的軟連接功能。 大家都知道,在linux中文件和文件夾是同樣的數據實體,可以用同樣的方法來做連接,在另外一個地方操作某個文件或目錄的連接,就達到了直接操作這個文件或目錄的作用。 首先,建立軟連接的方式是: ln -s sourcePath destinationPath把files文件夾放在myapp之外,并且在webapps中的某一個應用程序中,比如ROOT中建立一個files文件夾的軟連接,如: ln -s /usr/upload /usr/tomcat/webapps/ROOT/upload并且在ROOT的tomcat容器context中設定一個屬性 allowLinking="true" ,即可訪問 這樣,我們可以在myapp應用程序中,通過直接url調用,或者response的重定向方式,訪問到files中的文件,如: http://localhost:8080/upload/files/2010/3/15/010001.doc 這樣一來,訪問upload快捷方式就等于是訪問了upload文件夾,既沒有訪問外在資源沒有權限限制,又沒有使用File類讀寫數據流,不會有heap空間的限制,我們實現了易變數據文件的分離,并且沒有內存的消耗。讀寫500MB的文件,不需要把heap空間設置到500以上,只需要默認的64就可以了。 總結一下,利用操作系統的特性——軟連接,實現了數據文件從應用程序包中的分離,操作系統實現目錄文件訪問的跳轉,利用了文件I節點的修改,這屬于操作系統底層實現,比起利用JVM的應用層類File來實現讀寫要快10倍以上,節約JVM Runtime空間。
4、總結 我為了讓web應用程序易于維護,把版本發布的程序代碼和用戶上傳的數據文件分離,經過了對servlet重定向方法的思考和試驗,對File類文件流方法的試驗,對linux文件軟連接的方法試驗,最好決定使用最后一種,同時解決了文件維護性和運行效率的問題。
思考部分:
如果是分布式怎么辦?如果數據和程序不在同一個服務器上怎么辦?
其實web容器都有一個自身的解決方法:虛擬目錄。如果數據不在程序對應的那臺服務器上,只要在web容器中數據指向這個虛擬目錄就行。把虛擬目錄設置成共享。
新聞熱點
疑難解答