一、Javassist简介
- 是在 Java 中编辑字节码的类库。
- 它使 Java 程序能够在运行时定义一个新类, 并在 JVM 加载时修改类文件。
二、和反射的区别
- 反射的定义:是让程序在运行时,能够动态获取或修改对象的所有成员变量,调用对象的所有方法。
可以看到反射只可以获取和修改成员变量,可以调用方法,但不能修改方法。如果想要修改方法、新增属性就要使用到字节码增强技术,即:Javassist,可以通过修改字节码的方式来实现对类结构的修改。
三、背景介绍
用到这个技术是因为产品提了一个需求,要做一个excel表格导出,把用户基本信息和用户的成绩拼接在一起导出为一个表格。
因此我们利用Javassist技术copy一个新的类,把基本信息和成绩拼在一起,再加上@SheetColumn注解即可。
四、引入pom
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.26.0-GA</version>
</dependency>
五、newScoreCopyClass方法
这个方法是调用ClassBuilder类的方法。
可以看到先初始化了一个我们自己定义的ScoreClassBulder。resultLists是学生们的答题结果集合,因为我们只需要获取每道题的题目信息,获取第一个list就好,之后遍历把每一道题的名字通过addField方法注入到这个Builder类中,最后调用build方法完成构建。
private Class newScoreCopyClass(List<List<CompResultDto>> resultLists) throws Exception {
ScoreCopyBuilder subClassBuilder = new ScoreCopyBuilder();
List<CompResultDto> compResults = resultLists.get(i);
for (int i = 0; i < compResults.size(); i++) {
CompResultDto rlt = compResults.get(i);
String name = "score" + i;
subClassBuilder.addField(Integer.class, name, rlt.getPracticeName());
}
return subClassBuilder.build();
}
六、ScoreCopyBuilder类
这里我们具体来拆解一下ScoreCopyBuilder这个类
根据上面调用方法,核心方法有两个:addField注入属性,build方法完成构建。
6.1 addField方法
首先我们是自己定义了一个FieldWrapper内部类作为实体类,来存储每一个属性的3个信息。
字段类型是Integer,字段名称是之前方法调用时传入的score+i,sheetColumnValue也就是生成excel表格的表头内容。
可以看到这个方法只是把新增字段信息封装存入了list中,真正的构建过程应该是在build的时候发生。
List<FieldWrapper> fieldWrappers = Lists.newArrayList();
/**
* 添加一个Field
*