zoukankan      html  css  js  c++  java
  • 使用easyexcel时遇到Could not initialize class net.sf.cglib.beans.BeanMap$Generator

    可以访问 这里  查看更多关于 消息中间件 的原创文章。 

    1. 上一篇文章 Maven项目为什么会产生NoClassDefFoundError的jar包冲突 结合了大量的图解,详细介绍了Maven项目产生jar包冲突的原因,以及为什么在编译的时候不报错,在运行的时候会报错的场景分析;

    2. 本篇记录一下在项目开发中使用Alibaba的开源组件easyexcel做excel文件上传和下载功能时,遇到的一个jar包冲突问题的排查思路和解决办法。

    一. 问题现象

    在使用alibaba的easyexcel工具开发excel的上传和下载功能时,本机环境测试没有问题,部署到测试环境时,却发现下载excel文件的功能一直异常,查看后台服务报错日志如下:

    nested exception is com.alibaba.excel.exception.ExcelGenerateException: java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.beans.BeanMap$Generator] with root cause]
    java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.beans.BeanMap$Generator
    

      

    上一篇 Maven项目为什么会产生NoClassDefFoundError的jar包冲突 时 已经介绍过,看到 NoClassDefFoundError类似的异常时,大多数都是因为jar包冲突引起的。

    二. 问题排查流程

    由于本地开发环境无法浮现,所以只能从测试环境着手排查。

    1. 解压jar包

    登录项目部署的docker容器,解压项目jar包,将解压后的文件放入 app 文件夹里:

    [root@08e08117bd99 /]# cd /data/application/java
    [root@08e08117bd99 /data/application/java]# unzip app.jar -d app/

    2. 查找jar包里有没有cglib.beans.BeanMap类

    进入解压后的 app 目录,查找 cglib 包:

    [root@08e08117bd99 /data/application/java]# cd /app/BOOT-INF/lib
    $ ls -l | grep cglib
    -rw-r--r-- 1 root root 283080 Dec 7 2013 cglib-3.1.jar
    # 继续解压cglib包
    [root@08e08117bd99 /data/application/java/app/BOOT-INF/lib]# unzip -l cglib-3.1.jar | grep BeanMap
    336 12-07-2013 11:28 net/sf/cglib/beans/BeanMap$Generator$BeanMapKey.class
    3219 12-07-2013 11:28 net/sf/cglib/beans/BeanMap$Generator.class
    5008 12-07-2013 11:28 net/sf/cglib/beans/BeanMap.class
    1825 12-07-2013 11:28 net/sf/cglib/beans/BeanMapEmitter$1.class
    2090 12-07-2013 11:28 net/sf/cglib/beans/BeanMapEmitter$2.class
    1546 12-07-2013 11:28 net/sf/cglib/beans/BeanMapEmitter$3.class
    6339 12-07-2013 11:28 net/sf/cglib/beans/BeanMapEmitter.class

    发现,解压后的 jar包里是存在 cglib.beans.BeanMap$Generator 这个类。

    3. 继续看其它错误日志

    继续看错误日志,发现这段:

    class net.sf.cglib.core.DebuggingClassWriter has interface org.objectweb.asm.ClassVisitor as super class

    大概意思是:

    ClassVisitor 定义的是一个 interface,但是现在却作为一个父类(super class)被其它类继承了。

    这种情况表明,此时应该存在jar包冲突了:

    • ClassVisitor 在一个jar包中是一个 interface;

    • 在另一个jar包中却是一个 class。

    4. 从刚刚解压的项目jar包里查找asm包

    由于这个报错信息里包含asm,所以尝试查找包含asm的jar包:


    发现竟然有两个不同版本的jar包。。。

    三. 问题原因

    为什么一个项目打出的 jar包里会有两个 asm 包呢?

    1.项目哪些jar包依赖了asm包

    使用 Maven helper 搜索 asm:

    • easyexcel 2.1.6 依赖 cglib 3.1,cglib又依赖 asm 4.2;

    • 项目的springboot版本是2.0.0.M6,底层会依赖 asm 3.1。

    2. 为什么会有两个版本的asm包?

    从Maven 官方网站里搜索 asm 包:

    发现有两个 artifactId 都叫 asm(但groupId 不一样),点击第2个 asm,查看详情:

    也就是说 gropuId 为 asm 的包,从3.3.1版本后不再维护了,后续版本迁移到 gropuId为 org.ow2.asm 的 asm 包。

    看到这里,结论已经出来:

    • asm 包从3.3.1 往后,gropuId 发生了变更(由asm 变更 org.ow2.asm);

    • 由于项目使用的springboot版本是2.0.0,需要依赖asm3.0,easyexcel 2.1.6 依赖的是asm 4.2;

    • 导致 Maven 在打包的时候将这两个 asm包( artifactId 一样,但groupId 不一样)都打进去了。

    四. 问题解决​

    1. 该使用哪个版本的asm包?

    到现在为止,已经在排查过程中也得到了有用的报错信息

    class net.sf.cglib.core.DebuggingClassWriter has interface org.objectweb.asm.ClassVisitor as super class

    翻译过来就是: ClassVisitor 定义的是一个 interface,但是现在却作为一个父类(super class)被其它类继承了

    并且也理清了产生冲突的原因:项目jar包里包含两个asm包,现在要确定项目使用哪个版本的asm包。

    于是,从本机的 Maven 仓库里 分别找到 asm3.1 和 asm4.2 的包,并在 Idea 里打开ClassVisitor.class

    asm3.1:

    asm4.2:

    可以看到:

    • asm3.1的 ClassVisitor.class 是 interface,asm4.2的ClassVisitor.class是 class;

    • 再结合报错信息,确定项目应该使用 asm3.1 的包

    2. 怎么解决冲突

    由于asm 4.2是由 easyexcel 2.1.6 的依赖 cglib 3.1 引入的,因此降级 cglib 的版本,直接在pom.xml里引入低版本的 cglib 即可:

    <dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2</version>
    </dependency>
    

      

    更新依赖,再次使用Maven helper查看:

    ​可以看到:asm 版本已经降级成功。

    ​使用 Jenkins 编译、打包、部署至测试环境后,再次测试项目的 excel 下载功能已经可以正常使用,jar包冲突导致的问题已经解决。

    更多文章

    欢迎访问更多关于消息中间件的原创文章:

    关注微信公众号

    欢迎大家关注我的微信公众号阅读更多关于 消息队列 的原创文章:

  • 相关阅读:
    Navicat for SQLite之外键(05)
    UIButton
    多线程中的API
    UIImageView
    IOS中实现单例
    IOS中的多线程【二】— NSOperation和NSOperationQueue
    IOS中的多线程
    OC中新增的数据类型
    【转】c# DBF数据库导入导出实例
    【经验】学习新知识的经验
  • 原文地址:https://www.cnblogs.com/itdream/p/13613097.html
Copyright © 2011-2022 走看看