tomcat类加载器找不到jar包中的类问题分析与解决思路
2017-03-07 23:10
1101 查看
在这篇博文中java动态加载指定的类或者jar包反射调用其方法,介绍动态加载指定的类,当时我是拿URLClassLoader介绍的,当然可以自定义一个ClassLoader重写对应的方法,
不过这个有现成的比自己重写更强大为何不用。
话不多说,很久不写博客了,时间太紧了,起因还是一个网友私信我,说他反射创建某个对象时涉及其他jar中的类就会报ClassNotFound异常。
其实,我也遇到过这个问题,在项目中反射创建一个service也是这样的,涉及到第三方的jar可能就出这问题,当时我可是纠结了好久,花了好几天时间去解决,请教过诸多大神和网友,不过还是不行,问题沉溺了有一阵子。
网上很少又提到这个问题的。最近又请教几个有经验的网友说是没有findClass的原因,或是类名或者service的原因,应该是我描述问题没描述清楚吧。而且关键这个jar呀你不反射创建项目中用的好好的,就和昨天晚上私信我的那个网友一样,按JVM的双亲委托模型不应该啊,不熟悉的可以看看这译文个深入分析Java
ClassLoader原理,自定义或者URLClassLoader的父加载器是App ClassLoader,而这个jar或者类肯定它会找到并加载或者提前就加载到JVM里呢,怎么回事呢。
其实你如果这样想,我们都犯了一个严重的错误,就是我们不是单纯依托与JVM,程序结束就OK了,可能你测试的时候没问题,已到项目就有这问题。问题在于我们往往是运行在个应用服务器下,一般都是tomcat吧,而tomcat有自己的一套加载机制,有自己一些加载器,我们忽略这个因素才是导致了问题发生的根本原因。
我们忽略了tomcat内部自定义的类加载器只想到了JVM的那几个加载器,tomcat有个叫webApp的加载器它是先加载WEB-INF/classes后在加载WEB-INF/lib,但它的父加载器是它的common加载器,comon的父加载器是system加载器(和JVM的应用程序加载器功能差不多,不过指定了其他tomcat目录下的加载,大家可以看看官网上的英文文档),但是源码中这个加载器是URLClassLoader的子类,而URLClassLoader默认父加载tomcat下是它的system加载器这么设计和tomcat的<Loader
delegate="true"/>配置有关,默认为无为false,会直接委托给tomcat的system加载器加载system委托最顶层的Bootstrap加载器(差不多是JVM里起始加载器和扩展加载器的合并),但不管怎么样,项目在tomcat下自定义的或者URLClassLoader加载默认父加载器都不会是tomcat的webApp加载器而是system加载器,或者自定义的加载器或URLClassLoader和tomcat的webApp加载器没有上下关系,所以动态创建类时设计到其他类时肯定会报CNF异常。
解决思路就是先获取当前类的Class,然后获取当前类的加载器,在自定义的加载器或者URLClassLoader加载器创建时指定为它们的父加载器,这样问题就会游刃而解了,可能平常我们测试写个简单的例子没遇到这个问题,因为我们那时的URLClassLoader或者自定义的加载器的父加载器都是JVM的第三次加载器即应用程序加载,它是专门加载classpath下边的或者指定的类或者jar的,依照双亲委托模型,肯定会找到引入路径的那个类或者jar的。
或者我们使用Class.forName()的方式来动态加载指定的类,就不会存在这个问题,因为这种方式一方面是能初始化类的静态东西,再就是重要一点,就是采用的加载当前所在类的加载器来加载你指定的类,这样你在tomcat下那就是它的webApp加载器啊,肯定不再出现这个问题,可能直接就从缓存里找到了。
不过这个有现成的比自己重写更强大为何不用。
话不多说,很久不写博客了,时间太紧了,起因还是一个网友私信我,说他反射创建某个对象时涉及其他jar中的类就会报ClassNotFound异常。
其实,我也遇到过这个问题,在项目中反射创建一个service也是这样的,涉及到第三方的jar可能就出这问题,当时我可是纠结了好久,花了好几天时间去解决,请教过诸多大神和网友,不过还是不行,问题沉溺了有一阵子。
网上很少又提到这个问题的。最近又请教几个有经验的网友说是没有findClass的原因,或是类名或者service的原因,应该是我描述问题没描述清楚吧。而且关键这个jar呀你不反射创建项目中用的好好的,就和昨天晚上私信我的那个网友一样,按JVM的双亲委托模型不应该啊,不熟悉的可以看看这译文个深入分析Java
ClassLoader原理,自定义或者URLClassLoader的父加载器是App ClassLoader,而这个jar或者类肯定它会找到并加载或者提前就加载到JVM里呢,怎么回事呢。
其实你如果这样想,我们都犯了一个严重的错误,就是我们不是单纯依托与JVM,程序结束就OK了,可能你测试的时候没问题,已到项目就有这问题。问题在于我们往往是运行在个应用服务器下,一般都是tomcat吧,而tomcat有自己的一套加载机制,有自己一些加载器,我们忽略这个因素才是导致了问题发生的根本原因。
我们忽略了tomcat内部自定义的类加载器只想到了JVM的那几个加载器,tomcat有个叫webApp的加载器它是先加载WEB-INF/classes后在加载WEB-INF/lib,但它的父加载器是它的common加载器,comon的父加载器是system加载器(和JVM的应用程序加载器功能差不多,不过指定了其他tomcat目录下的加载,大家可以看看官网上的英文文档),但是源码中这个加载器是URLClassLoader的子类,而URLClassLoader默认父加载tomcat下是它的system加载器这么设计和tomcat的<Loader
delegate="true"/>配置有关,默认为无为false,会直接委托给tomcat的system加载器加载system委托最顶层的Bootstrap加载器(差不多是JVM里起始加载器和扩展加载器的合并),但不管怎么样,项目在tomcat下自定义的或者URLClassLoader加载默认父加载器都不会是tomcat的webApp加载器而是system加载器,或者自定义的加载器或URLClassLoader和tomcat的webApp加载器没有上下关系,所以动态创建类时设计到其他类时肯定会报CNF异常。
解决思路就是先获取当前类的Class,然后获取当前类的加载器,在自定义的加载器或者URLClassLoader加载器创建时指定为它们的父加载器,这样问题就会游刃而解了,可能平常我们测试写个简单的例子没遇到这个问题,因为我们那时的URLClassLoader或者自定义的加载器的父加载器都是JVM的第三次加载器即应用程序加载,它是专门加载classpath下边的或者指定的类或者jar的,依照双亲委托模型,肯定会找到引入路径的那个类或者jar的。
或者我们使用Class.forName()的方式来动态加载指定的类,就不会存在这个问题,因为这种方式一方面是能初始化类的静态东西,再就是重要一点,就是采用的加载当前所在类的加载器来加载你指定的类,这样你在tomcat下那就是它的webApp加载器啊,肯定不再出现这个问题,可能直接就从缓存里找到了。
相关文章推荐
- java动态加载指定的类或者jar包反射调用其方法-涉及其他jar中的类就报ClassNotFound问题分析及解决思路
- java动态加载指定的类或者jar包反射调用其方法-涉及其他jar中的类就报ClassNotFound问题分析及解决思路
- SDK Manager 打不开, "系统找不到指定路径 " "Unable to access jarfile lib\archquery.jar"问题的解决办法
- 解决Spring Boot 使用Maven打包之后运行jar找不到主属性清单的问题
- YARN环境中应用程序JAR包冲突问题的分析及解决
- 解决找不到sun.misc.BASE64Encoder 的jar包问题
- 阿里云数据库结构分析与“脑裂”问题的解决思路
- Melis系统崩溃问题分析以及解决思路
- 6 个 Linux 运维典型问题,大牛的分析解决思路在这里
- Mac OS X安装JDK1.6及相关备忘 解决了找不到tools.jar的问题
- 6 个 Linux 运维典型问题,大牛的分析解决思路在这里 【转】
- JVM 出现如下异常时的解决思路(类冲突,jar包冲突等问题)
- 从Sell线上线程数告警问题解决的过程谈ThreadDump分析的思路
- PHP新建类问题分析及解决思路
- 智器TEN2 Plus第一版本问题列表分析及解决思路
- 解决 分析 window server2008 下找不到 word组件的问题
- SDK Manager 打不开, "系统找不到指定路径 " "Unable to access jarfile lib\archquery.jar"问题的解决办法
- SDK Manager 打不开, "系统找不到指定路径 " "Unable to access jarfile lib\archquery.jar"问题的解决办法
- C#.NET验证码智能识别学习笔记---06 解决java jre问题:JTessBoxEditor.jar打开的时报找不到或无法加载主类 com.sun.tools.javac.Main错误