該文章首發於 https:////www.cnblogs.com/steamer/articles/12500645.html
轉載注明出處!
問題描述:使用了別人整理的applicationContext.xml和springmvc.xml文件,大概如下(只放了applicationContext.xml)
然后Eclipse自動開始加載一些東西,幾分鍾后其他都加載完畢,還剩下兩個進程遲遲不動,根據以往的經驗,肯定是加載不出來了,卡住進程大概如下,
還有的人出現報無法加載Spring.xsd的錯誤(org.sax.SAXParseExptation:Failed to read schema document),我沒有遇到
解決辦法:將版本號改為你Spring工具包(jar包)內對應的版本即可解決問題
比如你的Libraries目錄下找到spring-xx包打開
那么相應的
改好后關閉eclipse重新打開就好了,至於為什么明明有4.2版本的xsd卻還是加載不出來,我也不會是很清楚,猜測應該默認尋找最新的xsd版本,如果
有知道原因的也希望能在評論區留言交流。
還有一種辦法就是把xsd約束文件全部換成本地的,工作量大而且非常麻煩,我不推薦這種辦法,這里也不再贅述
特別說明:如果你的是maven項目遇到這個問題,應當修改為你的maven插件包里下載的相應版本,插件包一般設置在maven安裝目錄,也有可能你
的是別的目錄,反正是自己設置的應該自己能找到。
接下來是枯燥的原理解釋:
問題發生的主要原因就是Spring服務器資源訪問不到,就像這樣
要明確的一點是:Spring在加載xsd文件時總是先試圖從本地查找xsd文件(Spring的jar包中包含部分必要的xsd文件),如果沒有找到,就會轉向URL下載指定的路徑下載,並不是直接去站點下載,這很合理也很好理解。Spring加載xsd文件的類是PluggableSchemaResolver,你可以查看他的源碼來驗證。另外可以在log4j中添加下面的代碼查看日志來驗證:
另外,當你的項目是maven項目時,出現類似的問題其他博主有解釋,轉載一篇如下http://www.360doc.com/content/15/0113/11/3639038_440376349.shtml(內容有些老,沒做驗證)
-----------------------這是不怎么看得到的分割線------------------------------
現在基本上都是采用maven來進行開發管理,我有如下需求:
需要把java工程打成可執行的jar包,必需把依賴的jar包也一起打包。
而maven默認的package命令構建的jar包中只包括了工程自身的class文件,並沒有包括依賴的jar包。
可以通過配置maven-assembly-plugin插件來打包,pom具體配置如下:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<!--<addClasspath>true</addClasspath>-->
<mainClass>com.xxx.MainClass</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>src/main/assembly/package.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
其中<mainClass></mainClass>的值表示此工程的入口類,也就是包含main方法的類。
配置完pom后可以通過執行mvn assembly:assembly命令來啟動插件進行構建。
構建成功后會生成jar包,這樣我們就可以在命令行中通過java -jar XXX.jar來運行jar件了。
不過使用此插件會有一些問題:
工程中依賴了spring框架的jar包,打包成功后使用命令來調用jar包時報錯如下(內網環境):
org.xml.sax.SAXParseException: schema_reference.4:
Failed to read schema document 'http://www.springframework.org/schema/beans/spring-beans-3.0.xsd',
because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
究其原因,在網上找到一篇文章對此有比較詳細的解釋:
https://www.cnblogs.com/steamer/articles/12500645.html
簡單來說就是spring在啟動時會加載xsd文件,它首先會到本地查找xsd文件(一般都會包含在spring的jar包中),如果找不到則會到xml頭部定義的url指定路徑下中去尋找xsd,如果找不到則會報錯。
附:在spring jar包下的META-INF文件夾中都會包含一個spring.schemas文件,其中就包含了對xsd文件的路徑定義,具體如下圖所示:
由於我的工程在內網,所以通過url路徑去尋找肯定是找不到的,但是比較奇怪的是既然spring的jar包中都會包含,那為什么還是找不到呢?
原來這是assembly插件的一個bug
該bug產生的原因如下:
工程一般依賴了很多的jar包,而被依賴的jar又會依賴其他的jar包,
這樣,當工程中依賴到不同的版本的spring時,在使用assembly進行打包時,只能將某一個版本jar包下的spring.schemas文件放入最終打出的jar包里,這就有可能遺漏了一些版本的xsd的本地映射,所以會報錯,所以一般推薦使用另外一個插件(maven-shade-plugin)來打包。
shade插件打包時在對spring.schemas文件處理上,它能夠將所有jar里的spring.schemas文件進行合並,
在最終生成的單一jar包里,spring.schemas包含了所有出現過的版本的集合。
maven-shade-plugin插件配置如下:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.xxx.MainClass</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
上面這段配置意思是把spring.handlers和spring.schemas文件以append方式加入到構建的jar包中,這樣就不會存在出現xsd找不到的情況。
配置完pom后,調用mvn clean install命令進行構建,構建成功后打開工程target目錄,發現生成了2個jar包,
一個為:original-XXX-0.0.1-SNAPSHOT.jar,
另一個為:XXX-0.0.1-SNAPSHOT.jar,
其中 original...jar里只包含了工程自己的class文件,而另外的一個jar包則包含了工程本身以及所有依賴的jar包的class文件。
我們只需要使用第二個jar包就可以了。