Tomcat类加载问题(一)

本文记录了一次在Tomcat环境中遇到的类加载问题,涉及插件机制、类加载顺序和双亲委派原则。问题源于同一jar包在不同目录下导致的不同类加载器加载了不同版本的接口,从而引发ClassCastException。解决方案包括调整jar包位置或在启动后设置上下文类加载器。
摘要由CSDN通过智能技术生成

Tomcat类加载问题(一)

最近有个同事在公司碰到了一个关于类加载的问题拉我一起看了一下,研究后发现挺经典的,写篇笔记记录一下。

问题现象

这个应用是一个框架型的应用,提供了一种插件机制,可以通过注册jar包插件进行一些定制化的数据分析入库操作。运行背景:
1、定制了插件A,jar包为xxx_plugin.jar
2、插件A中调用了CBB的jar包,xxxx_cbb.jar
3、web应用创建任务过程中也同样调用了xxxx_cbb.jar
4、任务由其他应用App_n调用此应用的接口,接口通过识别对应的字段选取插件创建任务通过反射获取插件运行实例放到队列中,插件运行实例继承与接口Interface_C,放到队列时会强制转换成接口Interface_C。
问题现象:
在插件A中初始化了实例Impl_B,此实例继承了接口Interface_C,在返回任务实例的时候把Impl_B强制转换成Interface_C实例返回,但是在强制转换时抛出了ClassCastException。

问题分析

通过调试发现,代码中获取的实例是对应正确的类的实例,转换的接口C也的确有实现关系,但是强转的时候抛异常,那只能说明插件中加载的Interface_C与强制转换的目标Interface_C是由不同的类加载器加载的,所以并不是同一个Interface_C,强制转换失败。
我翻了一下代码目录,当前应用目录如下:
${catalina_base}
  -lib
    -xxx_cbb.jar
  -plugins
    -xxx_plugin.jar
  -webapps
    -ROOT
      -WEB-INF
        -lib
          -xxx_cbb.jar

其中:${catalina_base}/lib为tomcat的common.loader目录
可以发现,xxx_cbb.jar在webapp目录的lib下,与common.loader的目录下均存在,很有可能就是这个原因导致的。

问题重现

之前记得tomcat的类加载是比较特殊的,webapp的类加载是不遵勖双亲委派原则的,查资料看了一下,大概知道问题所在。
tomcat类记载机制
当应用需要到某个类时,则会按照下面的顺序进行类加载:

1 使用bootstrap引导类加载器加载

2 使用system系统类加载器加载

3 使用应用类加载器在WEB-INF/classes中加载

4 使用应用类加载器在WEB-INF/lib中加载

5 使用common类加载器在CATALINA_HOME/lib中加载
因此,如果插件的Interface_C是由SystemClassLoader加载,而webApp的Interface_C是由WebAppClassLoader加载,那么进行强制转化时必然报错。
根据这个分析,模拟了一下问题:
文件目录:
目录结构

代码:

import package1.Interface1;

import java.io.File;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class Main {
   
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
   
        Thread.currentThread().setContextClassLoader(myPluginClassLoader(Thread.currentThread().getContextClassLoader()));
        ClassLoader myWebappClassLoader = myWebappLoader()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值