admin管理员组文章数量:1794759
JavaAssist的进阶使用
JavaAssist的进阶使用 1、 JavaAssist的介绍与常见使用方法 众所周知,JavaAssist和CGlib作为两个著名的操作Java的ByteCode方式,笔者认为JavaAssist更加灵活些,而CGlib更偏向定制化的应用,比如SpringBoot;而JavaAssist有一级项目吗?笔者知道的有Dubbo和Mybaits。我们先看JavaAssist的常用功能。 1.1 ClassPool的获取 通常我们用以下方式来获取默认ClassPool池: ClassPool pool = ClassPool.getDefault(); 而ClassPool还支持级联Pool: ClassPool pool = ClassPool.getDefault(); ClassPool child = new ClassPool(pool); 1.2 ClassPool创建Class与获取Class ClassPool创建或者获取的Class为CtClass,其中创建Class按照以下的方式: CtClass ctClass = pool.makeClass(“com.javaassisttest.test”); 而获取已有的Class方式为: CtClass ctClass = pool.get(“com.javaassisttest.test”); 在获取Class的时候,可能需要注意的是:当Class使用自定义的ClassLoader加载的时候,这时候由于JavaAssist使用的是AppClassLoader的加载,因此是找不到该class,需要添加ClassPath,添加ClassPath的方式如下: pool.appendClassPath(“路径”); 可支持多次添加。 1.3 ClassPool的Import Pool支持以下方式进行import: pool.importPackage(“java.util”); 但是,笔者的尝试是经常会产生比较奇怪的反编译代码,笔者建议还是采用完成的名称来定义更为合适。 2、 CtClass中的CtMethod与CtField 我们知道在Class可能存在成员变量和方法,我们可以通过以下方式进行成员变量的添加 CtField f = CtField.make(String.format(“private %s %s;”, field.getTypeName(), field.getName()), ctClass); ctClass.addField(f); 同样,我们可以通过以下方式进行方法的添加: String methodName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1); CtMethod get = CtMethod.make(String.format(getMethod, field.getTypeName(), methodName, field.getName()), ctClass); ctClass.addMethod(get); CtMethod set = CtMethod.make(String.format(setMethod, methodName, field.getTypeName(), field.getName()), ctClass); ctClass.addMethod(set); 这里是get和set方法的添加,其中getMethod和setMethod的定义如下: private final static String getMethod = “public %s get%s() { return %s;}”; private final static String setMethod = “public void set%s( %s $v) { %s = $v;}”;
至此,我们把JavaAssist的基本功能就讲解完了,下面我们还是进阶的部分。 3、 两个例子来看进阶的操作 笔者使用JavaAssist需要创建如下两个类: 其中类一: @Data @Table(name = “goods”) public class TkGoods { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Column(name = "name") private String name; @Column(name = "color") private Integer color; @Column(name = "suit") private Integer suit; @Column(name = "state") private Integer state; @Column(name = "addTime") private Date addTime; @Column(name = "updateTime") private Date updateTime;} 类二: public interface TkGoodsDao extends Mapper {
} 也就是tkMybatis的两个类,这两个类有两种操作在上一节中没有说到: (1) 注解 (2) 泛型子类 3.1 注解的添加 JavaAssist是支持注解的添加的,给Class添加注解如下代码所示: AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag); Annotation annotation = new Annotation(“javax.persistence.Table”, constPool); annotation.addMemberValue(“name”, new StringMemberValue(entity.getDbName(), constPool)); annotationsAttribute.addAnnotation(annotation); ctClass.getClassFile().addAttribute(annotationsAttribute); 同理,我们还能给成员变量添加注解 CtField f = CtField.make(String.format(“private %s %s;”, field.getTypeName(), field.getName()), ctClass); AnnotationsAttribute fannotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag); Annotation fColumn = new Annotation(“javax.persistence.Column”, constPool); fColumn.addMemberValue(“name”, new StringMemberValue(field.getDbName(), constPool)); fannotationsAttribute.addAnnotation(fColumn); f.getFieldInfo().addAttribute(fannotationsAttribute); 这样我们就完成了注解的添加,注:有一类注解是在编译时执行的,比如lombok,这种注解就必须手动完成get和set方法了。 3.2 泛型子类 我们先看下面这个类 class List { T value; T get() { return value; } void set(T v) { value = v; } } 在JavaAssist的官网中,也是这个类的例子,这个例子告诉我们通过setGenericSignature去设置模板,具体的代码如下: ClassSignature cs = new ClassSignature( new TypeParameter[] { new TypeParameter(“T”) }); cc.setGenericSignature(cs.encode()); // <T:Ljava/lang/Object;>Ljava/lang/Object; 然而,对于泛型子类的方式,官网上却没有提及,诸多查找出来的答案也是无法完成想要的效果的。最后还是找到了这样的答案,如下代码所示: CtClass ctClass = pool.makeInterface(className); CtClass clsMapper = pool.get(Mapper.class.getName()); ctClass.setSuperclass(clsMapper); SignatureAttribute.ClassSignature cs = new SignatureAttribute.ClassSignature(null, null, new SignatureAttribute.ClassType[] {new SignatureAttribute.ClassType(Mapper.class.getName(), new SignatureAttribute.TypeArgument[]{new SignatureAttribute.TypeArgument(new SignatureAttribute.ClassType(clsEntity.getName()))})}); ctClass.setGenericSignature(cs.encode());
4、 留下的两个疑问 到此,JavaAssist的进阶功能就基本介绍完成了,细心的你一定会发现这两个类就是TkMybatis的两个类,那么 1、 我们知道通过tk.mybatis.spring.annotation.MapperScan进行Bean注入,这两个类自动生成的类用来做什么呢? 2、 如何把我们生成的两个类添加到Bean中形成MapperProxy,是Refresh吗? 具体见下一篇的分解,自动处理动态表单的标准化与插件化。
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
本文标签: 进阶JavaAssist
版权声明:本文标题:JavaAssist的进阶使用 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686792843a103611.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论