昨天在家裡整理我的寶貝硬盤時,發現之前的一個基於JSP結構的電子交易平台的源碼,而且還有數據庫,反正也沒事,於是就想弄一下,讓它跑起來。接下來,下載安裝Tomcat和SqlServer的JDBC驅動(JDK之前就安裝過),經過一系列的配置,通過測試JSP能夠正常運行,JavaBean也能夠正確運行,Servlet也能夠正確運行,看樣子環境應該沒有問題。緊接著關鍵的部分就要來到了。我把SqlServer的JDBC驅動的三個JAR包放到了系統的classpath裡,然後,啟動Tomcat,並且迫不及待的在浏覽器地址欄裡輸入http://localhost:80/IC/,靜靜地等待著系統的出現。系統終於跑起來了,可是看到的跟我的想象的不一樣,界面上凡是有對數據庫的訪問的地方都出現了“Thisconnectionhasnotbeenestablishedyet.”,很顯然問題出在和數據庫的連接上。
經過分析發現,系統對數據庫的訪問是透過一個JavaBean來實現的。於是,我把這個JavaBean的源碼拷到了類似於記事本一樣的文本編輯器裡,並且加了main方法,來測試這個類是否工作正常。編譯得到class文件後,用javaxxx來執行,從輸出來看,沒有問題。但問題到底出在哪裡呢?於是,我又把這段代碼拷貝到Eclipse的一個工程裡,編譯執行後,報的錯跟訪問JSP的錯是一樣的,進一步跟蹤發現,在Class.forName(“com.microsoft.jdbc.SQLServerDriver”);時報類沒有找到,也就是說沒有找到類SQLServerDriver,再打開mssqlserver.jar一看,類SQLServerDriver赫然在立,路徑也沒有錯。我明明在classpath裡加載了三個JAR包啊,為什麼在命令行方式可以找到,在Eclipse裡反倒沒有找到呢?太讓人困惑了!周末的好心情完全被這個問題攪亂了,並且暗暗下定決心,一定要解決而後快。接下來,就是上論壇問人,還有就是在QQ和MSN上找人問,同時,自己也在分析可能的原因,進行嘗試。
聯想到工作中經常把用到的JAR包都會加到項目的類路徑中,於是,我也把三個JAR包添加到項目的類路徑中,然後重新編譯執行,發現問題沒有了,輸出正常。此時,我就初步斷定問題出在Eclipse裡執行類時加載的包跟系統的classpath指定的不一致,也就是說系統的classpath指定的類根本就沒有加載到內存,所以就會報找不到類,而在命令行方式,加載的就是系統的classpath指定的包。問題雖然明確定位了,但具體是什麼原因,我還是無法解釋。結合在JSP裡,我如何在啟動Tomcat時先把三個jar包加載到內存呢?我寫了個批處理文件,內容是set classpath=E:\xxxxx\msbase.jar;E:\ xxxxx\mssqlserver.jar;E:\ xxxxx\msutil.jar;我在命令行方式下,先執行這個批處理,然後,在執行啟動Tomcat的命令,後來發現,依舊報錯,說明這樣加載jar包有問題。到這裡,我幾乎都想放棄了,想不到居然被這個classpath搞得焦頭亂額,郁悶啊!但要我放棄,還真是不服氣!還是休息一下,回頭再來!
在客廳轉了一下,弄了點東西吃了,感覺有點困,於是就睡去了。一覺睡了兩個小時,起來的時候天色已暗,於是,又回到計算機旁,想想怎樣才能搞定它!於是,在大腦裡搜索工作中跟classpath有關的一些問題,以及解決方法。依稀記得,在Jdk的jre\lib\ext裡的jar包,java是自己會自動加載的,於是,我又把三個jar包拷到這裡,重新啟動tomcat,在浏覽器地址欄裡輸入訪問地址,靜靜的等待以後,系統終於沒有報之前的錯誤了,數據庫連接正常了,終於跑起來了。我重重的舒了口長氣,不容易啊。
到這裡系統跑起來了,但classpath並沒有徹底搞明白,我只是繞開了這個問題。今天一上班,我就想問南哥,但考慮到星期一上午大家都會比較忙,我忍住了。在中午快吃飯的時候,我還是問了這個問題。南哥的解釋是,在命令行方式,java自己會加載系統的classpath裡指定的包,而在Eclipse等開發環境裡,系統加載的是開發環境的classpath。這個解釋,跟我的實驗情況完全吻合,聽起來也沒有問題。為了進一步確認在兩種場景下classpath加載內容有什麼不同,南哥建議我用System.getProperties()看看到底有什麼差異?當我比較兩種情況下的輸出時,困擾了我一天的classpath問題,徹底弄明白了:通過命令行方式,來java xxxx時,會加載系統的classpath裡的包,其方式是java.class.path=””,同時還會通過sun.boot.class.path=””的方式來加載jdk下的jre\lib\下的jar包,對於ext目下的包的加載,應該是通過java.ext.dirs=W:\jdk\jre\lib\ext來進行的,但這裡沒有具體的包名;通過IDE環境來執行java程序時,會加載環境指定的jar包。
編後:
在命令行方式下,通過我先執行加載環境的批處理,後啟動Tomcat和直接啟動Tomcat得到的兩份系統屬性,對比其中的java.class.path來看,兩者完全一樣,亦即在當前的使用場景下想通過批處理來加載jar包,是行不通的.進一步嘗試,在單純的命令行方式下通過批處理來加載jar包,然後執行java xxxx,跟蹤系統屬性得到的java.class.path跟批處理要求加載的完全一致.另一方面,在tomcat的webapp下建立自己的應用例如Test,然後在Test的WEB-INF目錄下,建立目錄lib,把你的jar包放到這裡,也可以讓tomcat找到你要加載的類.文中在前面提到,把jar放到jre\lib\ext\下系統能夠運行,說明也沒有問題,在tomcat的使用場景下,建議采用放到WEB-INF的lib目錄下的方式.這樣處理,很顯然的一個好處是增強了系統的可移植性.