單個(gè) tomcat 下運(yùn)行多個(gè) war 應(yīng)用, 問題與解決方法
公司內(nèi)有兩個(gè) Java web 應(yīng)用,最近需要去客戶處展示,需要安裝在一臺筆記本電腦上。
兩個(gè) Java web 應(yīng)用,都有些年頭了,最初使用 Java 1.6 開發(fā),現(xiàn)使用 Java 8 重新編譯。
有一臺 16G 內(nèi)存、500G 硬盤的筆記本,惠普戰(zhàn)66。嘗試將兩個(gè)Java web 應(yīng)用安裝在此電腦里同一個(gè) tomcat 內(nèi)。
想著很簡單,打包成 war 文件(分別是 zsso.war, pkg.war), 復(fù)制到 C:\java\apache-tomcat-9.0.52\webapps 目錄下,改些配置文件,啟動 tomcat 的 bin\startup.bat , 應(yīng)該就行了。
其中,zsso.war 是公司的一個(gè)單點(diǎn)登錄軟件產(chǎn)品,自帶用戶登錄、權(quán)限配置等功能。此次是 pkg.war 更改時(shí)間緊張,不想再去動權(quán)限配置功能,想著可以借用 zsso.war 的功能,節(jié)省點(diǎn)開發(fā)時(shí)間,就算免費(fèi)送客戶一套單點(diǎn)登錄系統(tǒng)好了。節(jié)省了開發(fā)時(shí)間,也是好的。
結(jié)果運(yùn)行報(bào)錯(cuò),pkg 能啟動起來,zsso 啟動失敗,tomcat 自帶的 docs, examples, host-manager,manager,ROOT 幾個(gè)應(yīng)用也啟動失敗。報(bào)錯(cuò)信息相同,均為 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,里面專門有一章節(jié) "XML Parsers and Java"。雖然沒看明白,這個(gè)與我們此次報(bào)錯(cuò)有什么關(guān)聯(lián)。但猜測,Java 中的 XML 解析相關(guān)類,與 class loader 緊密相關(guān)。
經(jīng)調(diào)查,pkg.war 中使用了 SAX XML 解析,而 zsso.war 中沒有使用。
推測 pkg.war 中使用了 SAX XML 解析,用了某個(gè)特定方式,導(dǎo)致影響了 zsso.war,也影響了 tomcat 自帶的幾個(gè) web 應(yīng)用及示例。
查找代碼,有如下:
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);
經(jīng)測試,去掉第一行代碼,問題解決。
最后回顧:
代碼行:
System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl");
影響了 tomcat 中的多個(gè) war 應(yīng)用,也影響了 tomcat 自帶的幾個(gè) web 應(yīng)用及示例。
之前 Java 1.6 時(shí),需要此行代碼。最新的 Java 8 ,不需要此行代碼。
因此,Java web 代碼中,應(yīng)避免/減少使用 System.setProperty(...);
======歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處, http://www.rzrgm.cn/jacklondon/

浙公網(wǎng)安備 33010602011771號