首页 > 编程语言 >javassisit提升反射效率

javassisit提升反射效率

时间:2024-09-20 20:21:26浏览次数:10  
标签:反射 return String rs 效率 user null public javassisit

Javassist简介

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京技术学院的数学和计算机科学系的 Shigeru Chiba 所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。

Javassist(JAVA编程ASSISTant)使Java字节码操作变得简单。 它是一个用Java编辑字节码的类库; 它使Java程序能够在运行时定义新类,并在JVM加载时修改类文件。 与其他类似的字节码编辑器不同,Javassist提供两个级别的API:源级别和字节码级别。 如果用户使用源级API,他们可以在不知道Java字节码规范的情况下编辑类文件。 整个API仅使用Java语言的词汇表进行设计。 您甚至可以以源文本的形式指定插入的字节码; Javassist即时编译它。 另一方面,字节码级API允许用户直接编辑类文件作为其他编辑器。

同ASM比较

同类型的字节码编辑框架还有如cjlib使用的ASM动态字节码技术,二者对比如下,目前主流的还是使用的ASM,因为生成字节码速度更快,所以运行起来ASM是会比javassist快很多,但是一般不会直接使用ASM,因为ASM是需要手写字节码。
高并发环境下,javassist能明显提升反射的效率,通过手写一段ORM代码实现反射

1.创建表结构

生成10000条模拟数据

CREATE TABLE `t_user`  (
  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `user_id` int(11) NOT NULL,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;



##创建存储过程批量生成1w条数据
CREATE PROCEDURE callback()
BEGIN
  DECLARE num INT;
  SET num = 1;
  WHILE
    num <= 10000 DO
    INSERT INTO t_user(user_id, user_name, `password`)
    VALUES( num,CONCAT("user_name", num),CONCAT("password", num));
    SET num = num + 1;
  END WHILE;
END; 
 
CALL callback;

2.加入maven依赖

 <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>

3.创建字段注解和实体类

创建数据库实体映射注解

/**
 * 数据表中的列
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {

    String name();
}
/**
 * @program: ormtest
 * @description: 用户实体
 * @author: xml
 * @create: 2021-01-08 09:04
 **/
public class UserEntity {
    @Column(name = "user_id")
    private Integer userId;
    @Column(name = "user_name")
    private String userName;
    @Column(name = "password")
    private String password;

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

3.反射和javassist对比

3.1反射实现

/**
 * @program: ormtest
 * @description: 应用002
 * @author: xml
 * @create: 2021-01-08 09:11
 **/
public class App001 {

    /**
     * 应用程序主函数
     *
     * @param argvArray 参数数组
     * @throws Exception
     */
    static public void main(String[] argvArray) throws Exception {
        (new App001()).start();
    }

    /**
     * 测试开始
     */
    private void start() throws Exception {
        // 加载 Mysql 驱动
        Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
        // 数据库连接地址
        String dbConnStr = "jdbc:mysql://192.168.81.129:3306/temp20210108?user=root&password=shineCoding&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC";
        // 创建数据库连接
        Connection conn = DriverManager.getConnection(dbConnStr);
        // 简历陈述对象
        final Statement stmt = conn.createStatement();


        // 获取开始时间
        final UserEntity_Helper userEntity_helper = new UserEntity_Helper();
        // 创建 SQL 查询
        // ormtest 数据库中有个 t_user 数据表,
        // t_user 数据表包括三个字段: user_id、user_name、password,
        // t_user 数据表有 20 万条数据
        String sql = "select * from t_user limit 200000";
        long t0 = System.currentTimeMillis();
        // 执行查询
        ResultSet rs = null;
        try {
            rs = stmt.executeQuery(sql);

            while (rs.next()) {
                userEntity_helper.create(UserEntity.class, rs);
                //
                // 关于上面这段代码,
                // 我们是否可以将其封装到一个助手类里??
                // 这样做的好处是:
                // 当实体类发生修改时, 只需要改助手类就可以了...
                //
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }


        // 获取结束时间
        long t1 = System.currentTimeMillis();

        // 关闭数据库连接
        stmt.close();
        conn.close();

        // 打印实例化花费时间
        System.out.println("实例化花费时间 = " + (t1 - t0) + "ms");
    }
}

实体转换工具类

/**
 * 用户实体助手类
 */
public class UserEntity_Helper {
    /**
     * 将数据集装换为实体对象
     *
     * @param rs 数据集
     * @return
     * @throws Exception
     */
    public <TEntity> TEntity  create(Class<TEntity> classType,ResultSet rs) throws Exception {
        if (null == rs) {
            return null;
        }

        // 创建新的实体对象
        UserEntity ue = new UserEntity();

        Field[] fields = ue.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Column annotation = field.getAnnotation(Column.class);
            if(null==annotation){
                continue;
            }
            String name = annotation.name();
            if(null==name||"".equals(name)){
                continue;
            }
            Object object = rs.getObject(name);
            if(null==object){
                continue;
            }

            field.set(ue, object);
        }
        
       
        return (TEntity)ue;
    }
}

3.2.javassist动态字节码实现

/**
 * @program: ormtest
 * @description: 应用002
 * @author: xml
 * @create: 2021-01-08 09:11
 **/
public class App002 {

    /**
     * 应用程序主函数
     *
     * @param argvArray 参数数组
     * @throws Exception
     */
    static public void main(String[] argvArray) throws Exception {
        (new App002()).start();
    }

    /**
     * 测试开始
     */
    private void start() throws Exception {
        // 加载 Mysql 驱动
        Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
        // 数据库连接地址
        String dbConnStr = "jdbc:mysql://192.168.81.129:3306/temp20210108?user=root&password=shineCoding&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC";
        // 创建数据库连接
        Connection conn = DriverManager.getConnection(dbConnStr);
        // 简历陈述对象
        final Statement stmt = conn.createStatement();
        // 创建 SQL 查询
        // ormtest 数据库中有个 t_user 数据表,
        // t_user 数据表包括三个字段: user_id、user_name、password,
        // t_user 数据表有 20 万条数据
        String sql = "select * from t_user limit 200000";

        // 执行查询
        ResultSet rs = null;
        AbstractEntityHelper abstractEntityHelper = EntityHelperFactory.getEntityHelper(UserEntity.class);
        // 获取开始时间
        long t0 = System.currentTimeMillis();
        try {
            rs = stmt.executeQuery(sql);
            while (rs.next()) {
                abstractEntityHelper.create(rs);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 获取结束时间
        long t1 = System.currentTimeMillis();

        // 关闭数据库连接
        stmt.close();
        conn.close();

        // 打印实例化花费时间
        System.out.println("实例化花费时间 = " + (t1 - t0) + "ms");
    }
}

抽奖实体转换工具类

/**
 * @program: ormtest
 * @description: 抽象助手类
 * @author: xml
 * @create: 2021-01-08 10:13
 **/
public abstract class AbstractEntityHelper {

    /**
     * 将数据集转换为实体对象
     *
     * @param rs 数据集
     * @return
     *
     */
    public abstract Object create(ResultSet rs) throws Exception;
}

javassist具体实现:实体转换工厂EntityHelperFactory

/**
 * @program: ormtest
 * @description: 实体工厂类
 * @author: xml
 * @create: 2021-01-08 10:14
 **/
public class EntityHelperFactory {

    private static final Map<Class<?>,AbstractEntityHelper> HELPER_MAP=new HashMap<Class<?>, AbstractEntityHelper>();
    /**
     * 私有化类默认构造器
     */
    private EntityHelperFactory() {
    }

    /**
     * 获取帮助
     *
     * @param entityClazz 实体类
     * @return
     */
    public static AbstractEntityHelper getEntityHelper(Class<?> entityClazz) {
        // 这里需要全新设计,

        if(null==entityClazz){
            return null;
        }

        if(null!=HELPER_MAP.get(entityClazz)){
            return HELPER_MAP.get(entityClazz);
        }

        // 接下来就该请出 javassist 了!

        ClassPool pool = ClassPool.getDefault();//获取类池 用于创建CtClass
        pool.appendSystemPath();
        //导入包
        //        import com.shine.entity.Column;
        //        import java.lang.reflect.Field;
        //        import java.sql.ResultSet;
        pool.importPackage("com.shine.entity.Column");
        pool.importPackage("java.lang.reflect.Field");
        pool.importPackage("java.sql.ResultSet");
        //获取助手抽象类
        try {
            CtClass abstractEntityHelper = pool.getCtClass(AbstractEntityHelper.class.getName());
            //助手实现类名称
            final String extClassName=entityClazz.getName()+"_Helper";
            //创建实现类
            CtClass ctClass = pool.makeClass(extClassName, abstractEntityHelper);

            //创建无参构造器
            CtConstructor ctConstructor = new CtConstructor(new CtClass[0], ctClass);
            ctConstructor.setBody("{}");
            //加入构造器
            ctClass.addConstructor(ctConstructor);

            //创建函数代码
            final StringBuffer sb=new StringBuffer();
            sb.append("public Object  create(java.sql.ResultSet rs) throws Exception {\n");
            sb.append("if (null == rs) {\n" +
                    "            return null;\n" +
                    "        }\n");

            sb.append(entityClazz.getName()+"  ue = new "+entityClazz.getName()+"();\n");
            Field[] fields = entityClazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Column column = field.getAnnotation(Column.class);
                if(null==column){
                    continue;
                }
                String columnName = column.name();
                if(null==columnName||"".equals(columnName)){
                    continue;
                }
                String fileName=field.getName();
                sb.append("ue.set"+fileName.substring(0, 1).toUpperCase()+fileName.substring(1)+"(");
                if(field.getType().equals(Integer.class)){
                    sb.append("Integer.valueOf(rs.getInt(\""+columnName+"\"))");

                }else if(field.getType().equals(String.class)){
                    sb.append("rs.getString(\""+columnName+"\")");
                }
                sb.append( ");\n");
            }

            sb.append("return ue;\n");
            sb.append("}");
            CtMethod newMethod = CtNewMethod.make(sb.toString(), ctClass);
            ctClass.addMethod(newMethod);
            ctClass.writeFile("G:\\MySource");
            Class aClass = ctClass.toClass();
            AbstractEntityHelper destObj = (AbstractEntityHelper)aClass.newInstance();
            HELPER_MAP.put(entityClazz, destObj);
            return destObj;
        } catch (NotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (CannotCompileException e) {
            e.printStackTrace();
            return null;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        } catch (InstantiationException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}

对比之下每次执行查询时是用反射的方式,每次都会单独去跟实体匹配映射,是用javassist生成了代理类后被放入Map容器中缓存,效率大大提升,尤其在高并发的应用场景

标签:反射,return,String,rs,效率,user,null,public,javassisit
From: https://blog.csdn.net/ximaiyao1984/article/details/142303189

相关文章

  • ++i与i++在效率上的细微差别
    在一些特定的使用中,i++可能将原值用中间量存起来以待使用,下面看相关程序的汇编代码(使用gcc)。i++源程序:#include<stdio.h>intmain(){  inti=1;  printf("%d\n",i++);  return0;}i++汇编:main:.LFB0:  .cfi_startproc  endb......
  • 反射相关API
    反射的作用在不修改源码的情况下,扩展功能。程序在运行的时期,通过反射机制,获取类的所有内部信息,并且操作类的对象。Class类一个类在堆中只有一个Class对象,这个Class对象包含了类的完整结构信息反射技术是针对Class对象进行操作,在程序运行的时候,动态获取类中的所有成员[1......
  • 用于参数和计算效率的超细粒度图像识别的降采样插入层适配器
    2024年9月17日提交的论文《Down-SamplingInter-LayerAdapterforParameterandComputationEfficientUltra-Fine-GrainedImageRecognition》一.研究背景研究问题:这篇文章要解决的问题是超细粒度图像识别(UFGIR),即将对象分类到极其细小的类别中,例如区分同一物种内的......
  • 一款免费的AI搜索工具,提升您的搜索效率!
    开搜AI是一款面向大众的、直达答案的AI搜索引擎,它能够为用户问题提供直接、精准的答案,并自动总结重点、生成大纲、思维导图并下载。开搜AI功能特点精准结果呈现:开搜AI能够直接呈现精准结果,省去用户翻阅多个的繁琐过程。信息甄别真伪:具备比对纠错、信息甄别真伪、识别比对纠错......
  • 软件研发效能指标:全面提升研发效率
    老黄浅谈质量https://mp.weixin.qq.com/s?__biz=MzkwODc1ODc3Mg==&mid=2247483691&idx=1&sn=38cffe53bc90c0c7a1e15133facd57c9&chksm=c0c45ab0f7b3d3a6d38d96b9a277b25421dd0a31e3f913577d89de8e899dbe8de1c13898d0ff&token=2115451660&lang=zh_CN#rd在软件研......
  • Java反射概述
    反射Java反射(Reflection)是一种允许程序在运行时动态地获取有关类、方法和属性的信息,甚至可以对它们进行操作的机制。通过反射,程序可以在编译时并不知道一个类的具体信息的情况下,运行时获取该类的结构,并进行相应的操作。反射的核心是在运行时操作类和对象的元信息,这为开发提......
  • 【效率爆棚!Midjourney中文版,让你的创意如虎添翼!】
    Midjourney中文版是一款专为国内用户设计的图像生成与编辑平台,它不仅继承了国际版的强大功能,还针对国内网络环境和使用习惯进行了特别优化。这不仅是一款工具,更是每位创作者梦想中的魔法笔,将你的思绪与想象,瞬间编织成一幅幅令人惊叹的画作。MidjourneyAI超强绘画(原生态系统......
  • 掌握Python虚拟环境:隔离项目依赖,提升开发效率的必备指南
    虚拟环境是什么?        虚拟环境是Python中的一个概念,它允许开发者在一个隔离的环境中安装和使用Python包。每个虚拟环境都是一个独立的目录,其中包含特定版本的Python解释器和一系列独立的Python包。我们可以为每个项目创建一个虚拟环境,并为该环境安装所需的特定版......
  • JAVA进阶-枚举,类加载器,反射
    day15-枚举,类加载器,反射枚举为什么有枚举为了简洁的表示一些固定的值,Java就给我们提供了枚举。定义格式是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。格式publicenums{ 枚举项1,枚举项2,枚枚举项3;}定义枚举类要用关键字enum定义......
  • 哪个编程工具让你的工作效率翻倍?
    在日益繁忙的工作环境中,选择合适的编程工具已成为提升开发者工作效率的关键。不同的工具能够帮助我们简化代码编写、自动化任务、提升调试速度,甚至让团队协作更加顺畅。那么,哪款编程工具让你的工作效率翻倍?是智能的代码编辑器,强大的版本控制工具,还是那些让你事半功倍的自动化......