單個 tomcat 下運行多個 war 應用, 問題與解決方法


公司內有兩個 Java web 應用,最近需要去客戶處展示,需要安裝在一台筆記本電腦上。

兩個 Java web 應用,都有些年頭了,最初使用 Java 1.6 開發,現使用 Java 8 重新編譯。

有一台 16G 內存、500G 硬盤的筆記本,惠普戰66。嘗試將兩個Java web 應用安裝在此電腦里同一個 tomcat 內。

 

想着很簡單,打包成 war 文件(分別是 zsso.war, pkg.war), 復制到 C:\java\apache-tomcat-9.0.52\webapps 目錄下,改些配置文件,啟動 tomcat 的 bin\startup.bat , 應該就行了。

其中,zsso.war 是公司的一個單點登錄軟件產品,自帶用戶登錄、權限配置等功能。此次是 pkg.war 更改時間緊張,不想再去動權限配置功能,想着可以借用 zsso.war 的功能,節省點開發時間,就算免費送客戶一套單點登錄系統好了。節省了開發時間,也是好的。

 

結果運行報錯,pkg 能啟動起來,zsso 啟動失敗,tomcat 自帶的 docs, examples, host-manager,manager,ROOT 幾個應用也啟動失敗。報錯信息相同,均為 XML 解析的 class 找不到:

 

 1  org.apache.catalina.LifecycleException: Failed to initialize component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/zsso]]
 2     at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:112)
 3     at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
 4     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752)
 5     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:728)
 6     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
 7     at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:986)
 8     at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1857)
 9     at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
10     at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
11     at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
12     at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
13     at java.base/java.lang.Thread.run(Thread.java:832)
14 Caused by: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found
15     at java.xml/javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:194)
16     at java.xml/javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:147)
17     at java.xml/javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:226)
18     at java.xml/javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:219)
19     at org.apache.tomcat.util.digester.Digester.getFactory(Digester.java:474)
20     at org.apache.tomcat.util.digester.Digester.getParser(Digester.java:665)
21     at org.apache.catalina.startup.ContextConfig.init(ContextConfig.java:730)
22     at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:310)
23     at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:94)
24     at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:395)
25     at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:108)
26     ... 11 more
27 Caused by: java.lang.ClassNotFoundException: org/apache/xerces/jaxp/SAXParserFactoryImpl
28     at java.base/java.lang.Class.forName0(Native Method)
29     at java.base/java.lang.Class.forName(Class.java:427)
30     at java.xml/javax.xml.parsers.FactoryFinder.getProviderClass(FactoryFinder.java:119)
31     at java.xml/javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:183)
32     ... 21 more

 

查 tomcat 文檔,http://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html,里面專門有一章節 "XML Parsers and Java"。雖然沒看明白,這個與我們此次報錯有什么關聯。但猜測,Java 中的 XML 解析相關類,與 class loader 緊密相關。

經調查,pkg.war 中使用了 SAX XML 解析,而 zsso.war 中沒有使用。

推測 pkg.war 中使用了 SAX XML 解析,用了某個特定方式,導致影響了 zsso.war,也影響了 tomcat 自帶的幾個 web 應用及示例。

查找代碼,有如下:

1         System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl");
2 
3         SAXParserFactory parserFactory = SAXParserFactory.newInstance();
4         parserFactory.setValidating(false);
5         parserFactory.setNamespaceAware(false);
6 
7         RefrenceHandler mySaxParser = new RefrenceHandler();
8         SAXParser parser = parserFactory.newSAXParser();
9         parser.parse(refIs, mySaxParser);

 

經測試,去掉第一行代碼,問題解決。

 

最后回顧:

代碼行:

        System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl");

影響了 tomcat 中的多個 war 應用,也影響了 tomcat 自帶的幾個 web 應用及示例。

 

之前 Java 1.6 時,需要此行代碼。最新的 Java 8 ,不需要此行代碼。

因此,Java web 代碼中,應避免/減少使用 System.setProperty(...);

 

======歡迎轉載,轉載請注明出處, https://www.cnblogs.com/jacklondon/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM