编程人 cdmana.com

Javassist operation bytecode generating object bytecode

General data structure

UserEntity.java

package org.example;

public class UserEntity {
    @Column(name = "user_id")
    public int _userId;

    @Column(name = "user_name")
    public String _userName;

    @Column(name = "password")
    public String _password;

    @Override
    public String toString() {
        return "UserEntity{" +
                "_userId=" + _userId +
                ", _userName='" + _userName + '\'' +
                ", _password='" + _password + '\'' +
                '}';
    }
}

Column.java

package org.example;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String name();
}

 

1) Data initialization

package org.example.step00;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

/**
 *  Initialize the contents of the database table 
 */
public class Init {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String dbConnStr = "jdbc:mysql://localhost:3306/ormtest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT";
        Connection conn = DriverManager.getConnection(dbConnStr, "root", "jianan");

        String sql = "INSERT INTO t_user (user_name, password) VALUES (?, ?)";
        PreparedStatement ps = conn.prepareStatement(sql);

        long t0 = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            ps.setString(1, "jianan" + i);
            ps.setString(2, String.valueOf(i));
            ps.executeUpdate();
        }
        long t1 = System.currentTimeMillis();

        ps.close();
        conn.close();

        System.out.println(" Spend time :" + (t1 - t0) + "ms"); //  Spend time :18122ms
    }
}

2) Native jdbc operation ( Faster )

package org.example.step000;

import org.example.UserEntity;

import java.sql.*;

/**
 *  Native jdbc operation 
 */
public class App000 {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String dbConnStr = "jdbc:mysql://localhost:3306/ormtest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT";
        Connection conn = DriverManager.getConnection(dbConnStr, "root", "jianan");
        Statement stmt = conn.createStatement();

        String sql = "select * from t_user limit 200000";
        ResultSet rs = stmt.executeQuery(sql);

        long t0 = System.currentTimeMillis();

        while (rs.next()) {
            UserEntity ue = new UserEntity();

            ue._userId = rs.getInt("user_id");
            ue._userName = rs.getString("user_name");
            ue._password = rs.getString("password");
        }

        long t1 = System.currentTimeMillis();

        stmt.close();
        conn.close();

        System.out.println(" Spend time :" + (t1 - t0) + "ms");

    }
}

3) Complete the operation with reflection ( convenient , But it's slow , About time is original 4 times )

UserEntity_Helper020.java

package org.example.step020.entity;

import org.example.Column;
import org.example.UserEntity;

import java.lang.reflect.Field;
import java.sql.ResultSet;

public class UserEntity_Helper020 {
    public <T> T create(ResultSet rs, Class<T> t) throws Exception {
        if (null == rs) {
            return null;
        }

        T ue = t.newInstance();

        Field[] fArray = ue.getClass().getFields();

        for (Field f : fArray) {
            Column annoColumn = f.getAnnotation(Column.class);
            if (annoColumn == null) {
                continue;
            }

            String colName = annoColumn.name();
            Object colVal = rs.getObject(colName);

            if (colName == null) {
                continue;
            }

            f.set(ue, colVal);
        }

        return ue;
    }
}

Main.java

package org.example.step020;

import org.example.UserEntity;
import org.example.step010.entity.UserEntity_Helper;
import org.example.step020.entity.UserEntity_Helper020;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class App020 {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String dbConnStr = "jdbc:mysql://localhost:3306/ormtest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT";
        Connection conn = DriverManager.getConnection(dbConnStr, "root", "jianan");
        Statement stmt = conn.createStatement();

        String sql = "select * from t_user limit 200000";
        ResultSet rs = stmt.executeQuery(sql);

        UserEntity_Helper020 helper = new UserEntity_Helper020();

        long t0 = System.currentTimeMillis();

        UserEntity ue = null;
        while (rs.next()) {
            ue = helper.create(rs, UserEntity.class);
        }

        System.out.println(ue);


        long t1 = System.currentTimeMillis();

        stmt.close();
        conn.close();

        System.out.println(" Spend time :" + (t1 - t0) + "ms"); //  Spend time :85ms

    }
}

4) use javassist Optimize the code ( A little faster than the original )

AbstractEntityHelper.java

package org.example.step030.entity;

import java.sql.ResultSet;

public abstract class AbstractEntityHelper {
    public abstract Object create(ResultSet rs);
}

EntityHelperFactory.java

package org.example.step030.entity;

import javassist.*;
import org.example.Column;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

public class EntityHelperFactory {
    private static final Map<Class<?>, AbstractEntityHelper> _entityHelperMap = new HashMap<>();

    private EntityHelperFactory() {
    }

    public static AbstractEntityHelper getEntityHelper(Class<?> entityClass) throws Exception {
        if (null == entityClass) {
            return null;
        }

        AbstractEntityHelper helperObj = _entityHelperMap.get(entityClass);
        if (helperObj != null) {
            return helperObj;
        }

        ClassPool pool = ClassPool.getDefault();
        pool.appendSystemPath();

        pool.importPackage(ResultSet.class.getName());
        pool.importPackage(entityClass.getName());

        CtClass abstractEntityHelperClazz = pool.getCtClass(AbstractEntityHelper.class.getName());
        final String helperImplClazzName = entityClass.getName() + "_Helper";

        CtClass helperClazz = pool.makeClass(helperImplClazzName, abstractEntityHelperClazz);
        CtConstructor constructor = new CtConstructor(new CtClass[0], helperClazz);

        constructor.setBody("{}");
        helperClazz.addConstructor(constructor);

        final StringBuilder sb = new StringBuilder();
        sb.append("public Object create(java.sql.ResultSet rs) throws Exception {\n");
        sb.append(entityClass.getName())
                .append(" obj = new ")
                .append(entityClass.getName())
                .append("();\n");

        Field[] fArr = entityClass.getFields();

        for (Field f : fArr) {
            Column annoColumn = f.getAnnotation(Column.class);
            if (annoColumn == null) {
                continue;
            }

            String colName = annoColumn.name();
            if (f.getType() == Integer.TYPE) {
                sb.append("obj.")
                        .append(f.getName())
                        .append(" = rs.getInt(\"")
                        .append(colName)
                        .append("\");\n");
            } else if (f.getType().equals(String.class)) {
                sb.append("obj.")
                        .append(f.getName())
                        .append(" = rs.getString(\"")
                        .append(colName)
                        .append("\");\n");
            } else {

            }
        }

        sb.append("return obj;\n");
        sb.append("}");

        CtMethod cm = CtNewMethod.make(sb.toString(), helperClazz);

        helperClazz.addMethod(cm);

        Class<?> javaClazz = helperClazz.toClass();

        helperObj = (AbstractEntityHelper) javaClazz.newInstance();

        _entityHelperMap.put(entityClass, helperObj);

        return helperObj;
    }

}

Main.java

package org.example.step030;

import org.example.UserEntity;
import org.example.step020.entity.UserEntity_Helper020;
import org.example.step030.entity.AbstractEntityHelper;
import org.example.step030.entity.EntityHelperFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class App050 {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String dbConnStr = "jdbc:mysql://localhost:3306/ormtest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT";
        Connection conn = DriverManager.getConnection(dbConnStr, "root", "jianan");
        Statement stmt = conn.createStatement();

        String sql = "select * from t_user limit 200000";
        ResultSet rs = stmt.executeQuery(sql);

        AbstractEntityHelper helper = EntityHelperFactory.getEntityHelper(UserEntity.class);

        long t0 = System.currentTimeMillis();

        UserEntity ue = null;
        while (rs.next()) {
            ue = (UserEntity) helper.create(rs);
        }

        System.out.println(ue);

        long t1 = System.currentTimeMillis();

        stmt.close();
        conn.close();

        System.out.println(" Spend time :" + (t1 - t0) + "ms"); //  Spend time :24ms
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

Scroll to Top