设为首页 收藏本站
查看: 764|回复: 0

[经验分享] (转)tomcat下使用自定义类加载器遇到的问题

[复制链接]

尚未签到

发表于 2017-2-8 12:55:54 | 显示全部楼层 |阅读模式
http://freewind886.blog.163.com/blog/static/6619246420126141074308/
上周有用户在试用产品里一个与自定义classloader相关的功能时,发现在Junit下运行正常,部署到tomcat运行就会报错。
功能概述如下:
用户根据需要在可视界面上编写一个接口Hash的实现类,然后源码经过动态编译(借助jdk中的tools.jar包)在临时文件夹中生成class文件,读取该文件进入内存就可以存到数据库或者通过网络发送到其他Java进程。其他进程获取到class文件的byte[]后,通过一个自定义的classloader就可以创建出类实例。
现在的问题就在于这个自定义的classloader在Junit下可以加载byte[]创建类实例,而在tomcat下则抛出加载错误。之前曾了解过tomcat下的类加载机制和常见的Java应用不一样,所以开始的时候估计问题应该是出在这个地方,后来同事在断点调试下也明确了问题的原因。
推荐看这篇文章,里面详细介绍了Java的类加载机制:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 

借用里面的一张图:


DSC0000.jpg

  
对于直接通过java命令启动的Java应用,classpath里的类都由系统类加载器加载到进程中。我们产品中的自定义类加载器MyClassLoader在加载class文件的byte[]时,会检测到该类引入了接口Hash,MyClassLoader会将Hash的加载代理给父加载器(系统类加载器),系统类加载器在classpath中找到Hash的定义然后加载,接着整个加载操作就可以顺利的完成。
在tomcat环境下,类加载的机制就不同了,具体可见 http://blog.163.com/haizai219@126/blog/static/44412555200810111429791/
借用一图如下:
               Bootstrap
                   |
                System
                   |
                Common
               /       \
        Catalina      Shared
                             /... ...\
                webapp1     webappN 
在这种架构下,应用的类都由webappX类加载器来加载,而自定义的类加载器MyClassLoader的父加载器也就应该是webappX,那在加载网络传送过来的类定义的时候,也不会出现问题。最后在定位问题的时候,就是发现MyClassLoader的父加载器不是webappX,而是System,即上面提到的系统类加载器。
MyClassLoader(内部类)的实现如下:
 privatestaticclassMyClassLoaderextendsClassLoader{
     privatebyte[] classData =null;
     privateMyClassLoader(){
          super();
     }
     protectedClass<?> findClass(String name){
          return defineClass(name,this.classData,0,this.classData.length);
     }
     privateObject newInstance(String name)throwsInstantiationException,
               IllegalAccessException,ClassNotFoundException{
          return loadClass(name,true).newInstance();
     }
}

 
查看ClassLoader的无参构造函数,可以看到一行代码
this.parent = getSystemClassLoader();
这就是说,如果自定义的classloader如果不指定父加载器,则会被默认设置为系统类加载器。这就是问题的所在。
当MyClassLoader在加载Hash的实现类定义时,让父加载器(系统类加载器)去加载Hash接口定义。在tomcat的类加载机制下,系统类加载器实际上并不能加载应用功能相关的类,这就导致加载Hash失败。
修改的方法就是在创建MyClassLoader的时候,传入合适的父加载器。可以找一个使用了MyClassLoader的类,通过Class.getClassLoader()获取到所应该依附的父加载器。这样在tomcat或者普通的Java应用都可以解决加载出错的问题。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-339338-1-1.html 上篇帖子: 更深入的TOMCAT中文乱码解决之道,包括GET/POST(转) 下篇帖子: 数据库连接池c3p0 ,Proxool ,Druid ,Tomcat Jdbc Pool对比测试
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表