可以访问 这里 查看更多关于大数据平台建设的原创文章。

  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包冲突导致的问题已经解决。

关注微信公众号

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

使用easyexcel时遇到Could not initialize class net.sf.cglib.beans.BeanMap$Generator的更多相关文章

  1. 异常-----java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.core.KeyFactory

    SSH 类库问题 java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.proxy.Enhancer2009- ...

  2. java.lang.NoClassDefFoundError: Could not initialize class net.sf.json.util.JSONUtils

    页面报错: root: java.lang.NoClassDefFoundError: Could not initialize class net.sf.json.util.JSONUtils 出错 ...

  3. 异常:Caused by: java.lang.NoClassDefFoundError: Could not initialize class net.sf.log4jdbc.Properties

    参考文章: 使用Log4jdbc-log4j2监听MyBatis中运行的SQL和Connection 使用 log4jdbc格式化输出SQL,maven配置如下: <dependency> ...

  4. 【EasyExcel】使用easyExcel过程中,项目报错的解决集合

    报错:Can not close IO [ERROR] 2019-11-02 13:51:21.210 [ProExportSkuDataJob-1455-TaskThread-1] [com.dma ...

  5. 就因为加了Lombok的@Accessors(chain = true),bean拷贝工具类不干活了

    前言 这次新建了一个工程,因为 Lombok 用得很习惯,但以前的话,一般只用了@Data,@AllArgsConstructor,@EqualsAndHashCode等常规注解:那这个Accesso ...

  6. 动态代理(二)—— CGLIB代理原理

    前篇文章动态代理(一)--JDK中的动态代理中详细介绍了JDK动态代理的Demo实现,api介绍,原理详解.这篇文章继续讨论Java中的动态代理,并提及了Java中动态代理的几种实现方式.这里继续介绍 ...

  7. JAVA中JavaBean对象之间属性拷贝的方法

    JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,对于这种情况,可以采用以下几个简便方法处理. 下面对这 ...

  8. Java动态代理全面分析

    代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1  主题:规定代理类和真实对象共同对外暴露的接口: 2  代理类:专门代理真实对象的类: 3 ...

  9. Java动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

随机推荐

  1. 基于 JavaEmail 简单的发送邮件点到点,一对多(图片和附件)之多收件人,多少送人

    if(!StringUtil.isEmpty(message_type_to)){ if (message_type_to.contains(",")) { String[] sp ...

  2. Paper English

    论文中的英语 单词 a arange 整理 ambiguity 含糊的 aggregate 总量 auxiliary 辅助的 alleviate 缓解 aberrant 异常的 akin 类似的 Ac ...

  3. PyTorch上路

    PyTorch torch.autograd模块 深度学习的算法本质上是通过反向传播求导数, PyTorch的autograd模块实现了此功能, 在Tensor上的所有操作, autograd都会为它 ...

  4. Java高级篇反射和注解

    反射是什么? 反射的作用?能带来什么好处? 反射的使用? 注解的使用? 注解和反射配合实战...

  5. C#LeetCode刷题之#83-删除排序链表中的重复元素(Remove Duplicates from Sorted List)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3820 访问. 给定一个排序链表,删除所有重复的元素,使得每个元素 ...

  6. DRF内置认证组件之自定义认证系统

    自定义token认证 我们知道,在django项目中不管路由以及对应的视图类是如何写的,都会走到 dispatch 方法,进行路由分发, 在阅读 APIView类中的dispatch 方法的源码中,有 ...

  7. JavaScript基础-01

    1. Javascript是一门动态的.弱类型的.解释型的脚本语言 动态:数据类型在运行时决定 弱类型:变量数据的类型不是确定的,可以随意的进行改变: 解释型:相对编译型来说,编译型计算机在执行之前需 ...

  8. dota2输入法无候选框?

    win10自带的微软拼音在dota2中不会显示候选框,或者说是选词框. 这种情况下只能选择其他输入法. 我选择的是搜狗输入法(此随笔添加时的最新版),在dota2中有选词框. 网上有些人说要改兼容性, ...

  9. Mybatis-08-动态SQL

    动态SQL 什么是动态SQL? 根据不同的条件生成不同的SQL语句. if choose(where,otherwise) trim(where,set) foreach 搭建环境 create ta ...

  10. troubleshoot之:使用JFR分析性能问题

    目录 简介 GC性能事件 同步性能 IO性能 代码执行的性能 其他有用的event 简介 java程序的性能问题分析是一个很困难的问题.尤其是对于一个非常复杂的程序来说,分析起来更是头疼. 还好JVM ...