欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > javassisit提升反射效率

javassisit提升反射效率

2024/10/25 3:24:29 来源:https://blog.csdn.net/ximaiyao1984/article/details/142303189  浏览:    关键词: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()
BEGINDECLARE num INT;SET num = 1;WHILEnum <= 10000 DOINSERT 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();//获取类池 用于创建CtClasspool.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容器中缓存,效率大大提升,尤其在高并发的应用场景

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com