我們可能會用各種應用服務部署我們的Java應用,比如Tomcat、WAS、weblogic等。Tomcat和WAS可能會比較少遇到一些奇怪的問題,但是用weblogic部署項目則經常遇到一些比如包沖突問題,路徑問題等奇怪但又常見的問題。
今天我就講講關于weblogic部署Java項目包沖突的問題。下面我舉個例子:
當我在weblogic部署Java項目之後,啟動沒報任何錯,沒有異常。但是當我操作某個功能的時候頁面就報錯了:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcukDO4QjN3QTN30iM3ATOxITMxITMyEDM5EDMy0yM2kDNxATMvwVMwkTMwIzLcNjN5QTMwEzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
Root cause of ServletException.
java.lang.LinkageError: loader constraint violation: loader (instance of weblogic/utils/classloaders/ChangeAwareClassLoader)
previously initiated loading for a different type with name "javax/xml/namespace/QName"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at weblogic.utils.classloaders.GenericClassLoader.defineClass(GenericClassLoader.java:343)
at weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:302)
at weblogic.utils.classloaders.GenericClassLoader.findClass(GenericClassLoader.java:270)
at weblogic.utils.classloaders.ChangeAwareClassLoader.findClass(ChangeAwareClassLoader.java:64)
at weblogic.utils.classloaders.ChangeAwareClassLoader.loadClass(ChangeAwareClassLoader.java:49)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at org.apache.xmlbeans.XmlBeans.buildMethod(XmlBeans.java:174)
at org.apache.xmlbeans.XmlBeans.buildNoArgMethod(XmlBeans.java:190)
at org.apache.xmlbeans.XmlBeans.buildGetContextTypeLoaderMethod(XmlBeans.java:200)
at org.apache.xmlbeans.XmlBeans.<clinit>(XmlBeans.java:126)
at org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook$Factory.newInstance(Unknown Source)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.onWorkbookCreate(XSSFWorkbook.java:290)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:170)
at com.kayak.web.base.util.export.ExportExcelXSSF.export(ExportExcelXSSF.java:893)
at com.kayak.web.base.action.ExportExcelAction.exportExcel(ExportExcelAction.java:318)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at com.kayak.web.user.filter.LoginCertifyFilter.doFilter(LoginCertifyFilter.java:125)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at com.kayak.web.base.filter.LocalRequestFilter.doFilter(LocalRequestFilter.java:28)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3748)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3714)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2283)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2182)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1499)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:263)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
錯誤内容很長,但是要學會辨認,我剛開始就被一大堆錯誤誤導了。關鍵的都是下面的這個:
loader (instance of weblogic/utils/classloaders/ChangeAwareClassLoader)
previously initiated loading for a different type with name "javax/xml/namespace/QName"
大概意思就是“加載器之前啟動的時候加載了名字叫javax/xml/namespace/QName的其他類型的類”。其實轉換一下就是,在啟動的時候加載了一個javax/xml/namespace/QName類,我們現在要用的功能需要一個類也叫javax/xml/namespace/QName,但是這個不是我們真正想要的class。
從上面的意思可以知道,這就是有兩個相同包包路徑和類名稱的class,但是有一個想要的卻沒有,隻有一個我們并不想要的class。了解weblogic部署的同學都知道,weblogic加載了一個相同的class就不會在加載其他一樣的class了。
當我再操作一次的之後又報另一個錯(部分錯誤内容):
1 Root cause of ServletException.
2 java.lang.NoClassDefFoundError: Could not initialize class org.apache.xmlbeans.XmlBeans
3 at org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook$Factory.newInstance(Unknown Source)
4 at org.apache.poi.xssf.usermodel.XSSFWorkbook.onWorkbookCreate(XSSFWorkbook.java:290)
5 at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:170)
6 at com.kayak.web.base.util.export.ExportExcelXSSF.export(ExportExcelXSSF.java:893)
7 at com.kayak.web.base.action.ExportExcelAction.exportExcel(ExportExcelAction.java:318)
8 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
11 at java.lang.reflect.Method.invoke(Method.java:498)
就是說不能初始化class org.apache.xmlbeans.XmlBeans。但是我們不要被這個所誤導,關鍵還是在于上面的 javax/xml/namespace/QName ,就是因為這個沖突了是以才會導緻後面的問題發生。
我用 jfind.jar 在項目下的lib目錄下搜尋發現在axis-jaxrpc-1.4.jar下有 javax/xml/namespace/QName.class檔案。因為在jdk下的 rt.jar 下面也有 javax/xml/namespace/QName.class是以就會有兩個一樣的class檔案。
後面我發現在項目的 WEB-INF 下面有個 weblogic.xml 檔案,裡面就有一些關于weblogic的配置:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <weblogic-web-app>
3 <container-descriptor>
4 <prefer-web-inf-classes>true</prefer-web-inf-classes>
5 </container-descriptor>
6 <charset-params>
7 <input-charset>
8 <resource-path>/*</resource-path>
9 <java-charset-name>UTF-8</java-charset-name>
10 </input-charset>
11 </charset-params>
12 </weblogic-web-app>
這個配置檔案裡的第4行配置就是隻先附加元件目裡的class檔案,再加載weblogic的class,也就是因為這個配置而導緻了項目裡的axis-jaxrpc-1.4.jar下有 javax/xml/namespace/QName.class,jdk下的 rt.jar 下面也有 javax/xml/namespace/QName.class卻沒有加載到,但是後者才是程式所需要的。
是以,我就嘗試把weblogic.xml的第4行配置 改成 false,重新打war包,重新部署,然後發現問題解決了。
接着我又換了一種嘗試,就是weblogic.xml的第4行配置依然是true ,但是我把項目裡那個沖突的class所在的包 axis-jaxrpc-1.4.jar 删了,也重新打包部署,也沒有問題了。是以到此就把問題給解決了
總結:
1. 在weblogic中部署Java應用時,經常遇到包沖突問題,其實首先可以通過修改weblogic.xml配置來解決,另一種方式就是通過jfind.jar 找出沖突的class所在的包,直接把這個包删了,可以解決。
2. 包沖突問題都可以通過上面的兩種方式解決,還有就是 有時候可能會包找不到某個class檔案,其實很有可能就是因為class檔案沖突,以及先後加載的順序問題,導緻我們項目中真正需要的class檔案卻沒有被加載進來。