我们可能会用各种应用服务部署我们的 Java 应用, 比如 Tomcat,WAS,weblogic 等. Tomcat 和 WAS 可能会比较少遇到一些奇怪的问题, 但是用 weblogic 部署项目则经常遇到一些比如包冲突问题, 路径问题等奇怪但又常见的问题.
今天我就讲讲关于 weblogic 部署 Java 项目包冲突的问题. 下面我举个例子:
当我在 weblogic 部署 Java 项目之后, 启动没报任何错, 没有异常. 但是当我操作某个功能的时候页面就报错了:
后台报了这个错:
- 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 了.
当我再操作一次的之后又报另一个错 (部分错误内容):
- Root cause of ServletException.
- java.lang.NoClassDefFoundError: Could not initialize class org.apache.xmlbeans.XmlBeans
- 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)
就是说不能初始化 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 的配置:
- <?xml version="1.0" encoding="UTF-8"?>
- <weblogic-Web-App>
- <container-descriptor>
- <prefer-Web-inf-classes>true</prefer-Web-inf-classes>
- </container-descriptor>
- <charset-params>
- <input-charset>
- <resource-path>/*</resource-path>
- <java-charset-name>UTF-8</java-charset-name>
- </input-charset>
- </charset-params>
- </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 文件却没有被加载进来.
来源: https://www.cnblogs.com/sunshine6/p/10301372.html