公司內有兩個 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/