单个 tomcat 下运行多个 war 应用, 问题与解决方法

2021-08-27 12:08

 

公司内有两个 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 是公司的一个单点登录软件产品(Single Sign on, 缩写为 sso),自带用户登录、权限配置等功能。此次是 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 应用及示例。

查找代码,有如下:


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

SAXParserFactory parserFactory = SAXParserFactory.newInstance();
parserFactory.setValidating(false);
parserFactory.setNamespaceAware(false);

RefrenceHandler mySaxParser = new RefrenceHandler();
SAXParser parser = parserFactory.newSAXParser();
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.zheguisoft.com/staff_blogs/jacklondon_chen/2022, 及 https://my.oschina.net/jacklondon/blog/5209588, https://www.cnblogs.com/jacklondon