java.lang.ClassNotFoundException web專案載入時找不到類
1.概述
作為一個屌絲程式猿,怎麼能不會配置log4j呢,這樣在控制檯或者日誌檔案中很容易找到程式出BUG的地方。尤其是在控制檯輸出日誌的時候,那叫一個爽啊!
=-= 但是出現了問題,我擦,啟動web的時候spring建立上下文的時候居然會找不到類,我去,檢查了一下jar包,spring.jar spring-web.jar 都有啊,怎麼會找不到呢,我的jar包是放在web-inf/lib 下的,要是這樣都找不到的話,你要鬧哪樣!
於是急忙網上搜羅了一下,大多人犯得錯誤就是,直接通過build path去新增的jar包,這樣會導致web啟動的時候java.lang.ClassNotFoundException:
java.lang.ClassNotFoundException: org.springframework.web.util.Log4jConfigListener
為什麼會同時出現這兩種錯誤呢?是應為載入初始化log4j的時候需要使用spring的上下文,由於找不到ContextLoaderListener,所以沒辦法去初始化載入log4j。於是想到是不是因為沒有這個ContextLoaderListener類的jar包啊。感覺看到了光明似的,但是一檢視發現,我去,有啊,有這個包啊!這我就頓時無語了。
換了個思路,實在不行,俺就新建個專案,然後把所有的東西都搬遷到新專案中,clean了一下專案,clean一下tomcat,最後釋出了一下!T(太)M(萌)D(了)!居然好使了,你們說我能說啥呢?
雖然我的這種解決之道,很無奈,別說科學,甚至連神學都解釋不了。沒有辦法,Java這東西,大家都懂得,頭天晚上有問題,回家睡一覺,第二天上班居然好了。這尼瑪社麼邏輯!沒有辦法,藉此在這裡吐槽一下。
對於這類問題的規避,還是建議,大家操作的時候要謹慎,不要什麼東西都往專案裡面新增,一定要了解你新增的jar包,你需要什麼jar包,就新增什麼jar包。有時間後新增多了未必有好處。對,你猜對了,jar包衝突也是屌絲程式猿的必修課。
2.解決辦法
我就簡單的總結一下,這種問題的解決方法:
2.1 缺少jar包
對!如果出現ClassNotFoundException這個錯誤,你第一反應就是,缺少jar包,說明你還是個合格的程式猿。一般出現這中情況,50%是出現了缺少jar包的問題。你就可以去調戲一下度娘,問一下,為嘛沒有jar包,缺少了什麼jar包。2.2 jar包的位置匯入有問題
我們知道在匯入我們自己定義或者封裝的jar包是一般是通過build path 來新增一個jar包,但是當我們用這種方法匯入第三方提供的jar時,web project啟動時會出現這種找不到jar的情況。所以此時你需要手動將需要的jar放到web-inf/lib下,然後clean一下專案,重新發布一下,就OK了。2.3 jar包衝突
有一部分情況會因為jar包衝突或者jar包的版本不對出現問題。剛出現這個問題的時候,我也以為是版本不對發生了衝突,到官網一看,全是最新的jar包啊,應該不存在衝突!2.4 其他的情況
應對這種位置的情況,膽寒啊,有木有!最好的方法就是嘗試,clean一下專案,重新發布一下。不行的話重啟一下機器(當然這個不用擔心伺服器上,因為伺服器上是沒有eclipse環境的,有的問題在本地開發的時候會碰到而且不好解決的時候,有時候在伺服器上確實好用的)。如果再不行的話,最好的辦法就是新建專案,將檔案逐個遷移到專案中。在重新搞一下就OK了!什麼!還沒搞定,那最後一招了,找你們專案經理或者有經驗的同事幫助吧!3 Java載入順序
Java虛擬機器是根據Java ClassLoader(類載入器)決定如何載入Class。系統預設提供了3個ClassLoader
Root ClassLoader,ClassPath Loader,Ext ClassLoader
我們也可以編寫自己的ClassLoader,去載入特定環境下的Jar檔案。
能不能載入Jar,載入哪裡的Jar,是由ClassLoader決定的。
問題可能是 匯入的僅僅是jar包的引用,例如在eclipse中通過build path加進user lib……(類似快捷方式)
這種在Java Application中沒問題,但在web Application中可能會出現找不到類的異常。
在WEB Application中jar包最好放在webroot或webcontent下的lib資料夾內,特別是xml中用到的jar包。
4 log4j的配置
既然牽扯到log4j怎麼能不講它的配置方法搞清楚呢。網上版本眾多,當然你也可以去重新那些載入時的init方法,這裡推薦的是通過web.xml,使用預設的類載入方式去初始化log4j,比較原生態。web.xml如下:- <?xmlversion="1.0"encoding="UTF-8"?>
- <web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID"version="2.5">
- <welcome-file-list>
- <welcome-file>login.jsp</welcome-file>
- </welcome-file-list>
- <display-name>springMVC</display-name>
- <servlet>
- <servlet-name>spring</servlet-name>
- <servlet-class>
- org.springframework.web.servlet.DispatcherServlet
- </servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>spring</servlet-name>
- <url-pattern>*.do</url-pattern>
- </servlet-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:config/spring/applicationContext.xml</param-value>
- </context-param>
- <!-- log4j配置 -->
- <context-param>
- <param-name>log4jConfigLocation</param-name>
- <param-value>classpath:config/properties/log4j.properties</param-value>
- </context-param>
- <!-- log4j監聽器 -->
- <listener>
- <listener-class>
- org.springframework.web.util.Log4jConfigListener
- </listener-class>
- </listener><spanstyle="font-family: Arial, Helvetica, sans-serif;"></web-app></span>
對了從上面可以看出我的路徑實在src下的config/properties/log4j.properties中
log4j.properties 檔案如下- ### set log levels ###
- log4j.rootLogger = debug , stdout , D , E
- ### 輸出到控制檯 ###
- log4j.appender.stdout = org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.Target = System.out
- log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n
- ### 輸出到日誌檔案 ###
- log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
- log4j.appender.D.File = logs/log.log
- log4j.appender.D.Append = true
- log4j.appender.D.Threshold = DEBUG ## 輸出DEBUG級別以上的日誌
- log4j.appender.D.layout = org.apache.log4j.PatternLayout
- log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
- ### 儲存異常資訊到單獨檔案 ###
- log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
- log4j.appender.D.File = logs/error.log ## 異常日誌檔名
- log4j.appender.D.Append = true
- log4j.appender.D.Threshold = ERROR ## 只輸出ERROR級別以上的日誌!!!
- log4j.appender.D.layout = org.apache.log4j.PatternLayout
- log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
- <spanstyle="font-size:18px;">log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n 1的左右是沒有空格的,否則會報錯</span>