• 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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    }
    类二:
    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()); // 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开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    gin 集成 Swagger
    MeterSphere | 在接口自动化场景中,设置全局Token方法
    QT之tcp通信的简单例程
    webpack 压缩图片
    [C# ] 执行ping命令,获得网络状态
    Cholesterol-PEG-Amine CLS-PEG-NH2 胆固醇-聚乙二醇-氨基科研用
    常用的客户端和服务器端开发和测试工具
    [Linux] Screen的简单使用与中途退出保持运行
    别名获取方式记录
    CryptoPunks NFT 概览与数据分析
  • 原文地址:https://blog.csdn.net/m0_59092234/article/details/126105199