本人在此之前甚少接触weblogic,家里的weblogic也是第一次安装的。如果发现错误,敬请指正。
XX局点升级weblogic为11g,重新发包出错。现在记录一下处理的各种问题总结。
这是最早出现的问题,会出现类似下面的错误信息。
<2015-10-14 下午05时57分30秒 CST> 101017> <[ServletContext@1385406679[app:XXService module:XXService path:/XXService spec-version:2.5]] Root cause of ServletException.
java.lang.NoSuchMethodError: org.apache.commons.io.FileUtils.copyInputStreamToFile(Ljava/io/InputStream;Ljava/io/File;)V
这是weblogic部署最常见的问题,因为weblogic会自带I一些commons-*的包,这些包的版本还比较旧。具体可以见WEBLOGIC_HOME/modules目录的jar包。
添加weblogic.xml并设置prefer-web-inf-classes,即优先加载web应用下的类
<weblogic-web-app>
<container-descriptor>
<prefer-web-inf-classes>trueprefer-web-inf-classes>
container-descriptor>
weblogic-web-app>
这是使用prefer-web-inf-classes为true之后出现的问题,会出现类似下面的错误信息。
The validator class: "org.apache.taglibs.standard.tlv.JstlCoreTLV" has failed with the following exception: "java.lang.ClassCastException: weblogic.xml.jaxp.RegistrySAXParserFactory cannot be cast to javax.xml.parsers.SAXParserFactory".
这是weblogic部署很常见的问题,jstl会调用sax,sax是通过spi机制加载实现,获取是weblogic的实现,但它使用的是jdk自带的javax.xml.parsers.SAXParserFactory接口。
刚好web应用下也带了jar包xml-apis-1.x.jar,它也有javax.xml.parsers.SAXParserFactory这个接口。根据prefer-web-inf-classes的设置,jstl代码中用的是这个接口。
由此可知,使用classloader并不一样,无法转换。
删除WEB-INF/lib/xml-apis-1.x.jar后本地测试该问题恢复。
这是错误2解决后,继续解析spring时出现的问题。
这个问题和上面的差不多,太细就不深究了。
这种情况下,如果使用prefer-web-inf-classes为true,则需要排除存在QName的jar包并删除,但最后没有采用(改动太大,得不偿失)。
所以这次重新设置了prefer-web-inf-classes为false,但仍然优先加载commons,如下:
<weblogic-web-app>
<container-descriptor>
<prefer-web-inf-classes>falseprefer-web-inf-classes>
<prefer-application-packages>
<package-name>org.apache.commons.*package-name>
prefer-application-packages>
container-descriptor>
weblogic-web-app>
修改后本地测试ok,但发布到生产仍然失败。
错误3处理后,发布到生产仍然出错,报错信息如下:
18:44:57.337 [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR com.danga.MemCached.MemCachedClient - ++++ exception thrown while trying to get object from cache for key: init_error_key_0098
18:44:57.351 [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR com.danga.MemCached.MemCachedClient - com.xxx.hnxx.mybatis.entity.PlaterrorCodeBean
java.io.IOException: com.xxx.hnxx.mybatis.entity.PlaterrorCodeBean
at com.schooner.MemCached.ObjectTransCoder.decode(Unknown Source) ~[MemCached-2.6.6.jar:na]
at com.schooner.MemCached.AscIIClient.get(Unknown Source) [MemCached-2.6.6.jar:na]
at com.schooner.MemCached.AscIIClient.get(Unknown Source) [MemCached-2.6.6.jar:na]
at com.schooner.MemCached.AscIIClient.get(Unknown Source) [MemCached-2.6.6.jar:na]
at com.danga.MemCached.MemCachedClient.get(Unknown Source) [MemCached-2.6.6.jar:na]
at com.xxx.hnxx.cache.mencached.MemcacheManagerClient.get(MemcacheManagerClient.java:162) [MemcacheManagerClient.class:na]
上面的错误信息表示获取init_error_key_0098这个可以的时候失败,实际上这个key是在应用启动的时候就塞进去的。
这里有很多意想不到的事情,所以详细解释一下。
首先,这个出现了IOException让人联想到是否memcached服务器连接的问题。
实际上是因为库在实现java对象放入memcached的时候,有一个序列化/反序列化的过程(就是java自带的那个),在反序列化的时候找不到类会出现ClassNotFoundException,然后库将错误信息(就是一个类名)取出重新包装为IOException。
所以,这实际上是一个类找不到的问题。
再者,这个问题一开始在家里的weblogic没法重现。后来我重新检查了生产上weblogic的启动日志才发现了一些差异。
关键信息如下所示,生产上的weblogic在domain的lib目录也是有jar包的,而家里的是没有的。尝试修改把jar包也拷贝一份,果然重现。
<2015-10-14 下午06时44分36秒 CST> 000395> contents added to the end of the classpath:/weblogic/bea/user_projects/domains/PLATFORM_DOM/lib/MemCached-2.6.6.jar:/weblogic/bea/user_projects/domains/PLATFORM_DOM/lib/MyXMLSerializer-1.0.0.jar...
最后,这个问题就好解释多了。
序列化只是没什么特别。但是反序列化需要加载类,很明显system classloader(memcached库的classloader)是加载不到web应用中的类的。
有好几种方式,都列举一下:
<weblogic-web-app>
<container-descriptor>
<prefer-web-inf-classes>falseprefer-web-inf-classes>
<prefer-application-packages>
<package-name>org.apache.commons.*package-name>
<package-name>com.danga.*package-name>
<package-name>com.schooner.*package-name>
prefer-application-packages>
container-descriptor>
weblogic-web-app>
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// MemCachedClient实例化时,会持有SockIOPool.getInstance()单利的引用
cachedClient = new MemCachedClient((String)null, true, false, classLoader, null);
个人推荐的优先级是2 - 3 - 1, 尽量做到容器无关,并少动全局的东西。由于目前生产上的weblogic版本已经回退,待后续上生产验证。
WebLogic Server System classloader (classpath、/lib)
Filtering classloader (空)
Application classloader (EJB JARs、APP-INF/lib、APP-INF/classes、Manifest Class-Path in EJB JARs)
Web application classloader (WAR、Manifest Class-Path in WAR)