浏览 3352 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-01-12
//用户实体类,在后面的例子使用 public Class User{ private int autoId; private String name; public int getAutoId(){ return autoId; } public String getName(){ return name; Class<?> entityClass = Class.forName("User"); while(rs.next()){ Object entity = entityClass.newInstance(); //获取中实体的set方法,获取次方已经被缓存,通过缓存来查询的,此处只是用来说明问题 Method m = entityClass.getMethod("setName"); m.invoke(entity,rs.getString("name")); m = entityClass.getMethod("setAutoId"); m.invoke(entity,rs.getInt("AutoId")); } 我不知道oracle,bea和sun的ORM(简称,后面都会这样称呼)是不是也是这样实现,但是我知道我们公司早先的一款ORM和现在的一款ORM都是这样的方案来实现的。 【问题】 众所周知,在java中,通过反射调用方法相当的消耗资源,而且速度比起直接执行原方法要慢出好多,所以在hibernate中,如果大量的对象被频繁的创建时,在这一块性能是有所下降的,尤其是在高速运行的系统中。这就出现了,有人宁愿直接使用JDBC,也不使用hibernate的现象。 【突发奇想】 昨天在回家的公交车上,突然想到了早先我写的一个ORM。 两年前,那时我还在毕业后的第一家公司任职,我在非上班的时间写了一个非常简单的ORM(和iBATIS相像,离开那家公司后我才知道iBATIS,不过在写那个ORM时,我在网上搜寻过,没有找到合适我们那个报表系统的ORM,更没有看到iBATIS,就是iBATIS也不完全适合),后来我把它直接用到了公司的报表系统中,大家也方便了不少。其中有个CallBack类,其结构大致如下: public interface ResultSetCallBack{ public Object readEntity(ResultSet rs)throws SQLException; } 使用人是只要实现这个接口就行了,以User为例,应该是这样的: //当时我们的数据不同步,所以没有缓存 public UserCallBack implements ResultSetCallBack{ public Object readEntity(ResultSet rs)throws SQLException{ User user = new User(); user.setAutoId(rs.getInteger("autoId")); user.setName(rs.getString("name")); return object; } } 【想法】 如果把hibernate中“数据拷贝到实例”的方式改用ResultSetCallBack的方式,那hibernate在这一块的性能肯定会有所提高(不知道这一块的性能在整个性能中占据的地位)。 【实现方式】 ResultSetCallBack所有的实现类都使用动态生成的方法来完成,至于工具可以采用ASM或者javassit。 【我的实现】 至于怎么实现的"ResultSetCallBack实现类"的动态生成,昨天晚上在家我基本上写好了一个。贴出来主要的部分,其他的可以看附件: //EntitySetter.java //CallBack类 public interface EntitySetter { public void setEntityProperties(Object object,ResultSet rs) throws SQLException; } //JsEntitySetterGenerator.java //ResultSetCallBack实现类的动态生成类 public class JsEntitySetterGenerator { private final static ClassPool pool = ClassPool.getDefault(); static{ pool.importPackage("java.lang"); pool.importPackage("java.sql"); pool.importPackage("java.math"); pool.importPackage("java.util"); } private EntityMapping entityMapping; public JsEntitySetterGenerator(EntityMapping em) { super(); this.entityMapping = em; } public byte[] generateEntitySetter() throws CannotCompileException,IOException { CtClass c = generateEntitySetter0(); return c.toBytecode(); } public Class<?> generateEntitySetter(ClassLoader loader) throws CannotCompileException,IOException { CtClass c = generateEntitySetter0(); return c.toClass(loader, null); } private CtClass generateEntitySetter0() throws CannotCompileException{ String now = Long.toHexString(System.currentTimeMillis()); String className = "com/azk/entity/Z_" + now + "_" + entityMapping.getTableName(); CtClass c = pool.makeClass(className); List<EntityFieldMapping> list = entityMapping.getFieldMappingList(); String entityClassInternalName = entityMapping.getClass().getName(); StringBuffer src = new StringBuffer(); src.append("public void setEntityProperties(Object obj,ResultSet rs)"); src.append(" throws SQLException{"); src.append(entityClassInternalName).append(" entity = (").append( entityClassInternalName).append("obj);"); for (EntityFieldMapping mapping : list) { generateSetPropertySource(src, mapping); } src.append("}"); CtMethod method = CtMethod.make(src.toString(), c); c.addMethod(method); return c; } private void generateSetPropertySource(StringBuffer src, EntityFieldMapping mapping) { ResultSetSupportedDateType dt = mapping.getDateType(); if (ResultSetSupportedDateType.Byte == dt) { visitPrimitive(src, mapping, Byte.class); } else if (ResultSetSupportedDateType.Short == dt) { visitPrimitive(src, mapping, Short.class); } else if (ResultSetSupportedDateType.Int == dt) { visitPrimitive(src, mapping, Integer.class); } else if (ResultSetSupportedDateType.Long == dt) { visitPrimitive(src, mapping, Long.class); } else if (ResultSetSupportedDateType.Float == dt) { visitPrimitive(src, mapping, Float.class); } else if (ResultSetSupportedDateType.Double == dt) { visitPrimitive(src, mapping, Double.class); } else if (ResultSetSupportedDateType.Date == dt || ResultSetSupportedDateType.String == dt || ResultSetSupportedDateType.Timestamp == dt) { visitSimpleNonePrimitive(src, mapping); } else if (ResultSetSupportedDateType.Blob == dt) { visitBlobMethod(src, mapping); } else if (ResultSetSupportedDateType.Clob == dt) { visitClobMethod(src, mapping); } } private void visitSimpleNonePrimitive(StringBuffer src, EntityFieldMapping mapping) { String resultSetMethod = mapping.getDateType().getResultSetMethodName(); String propertyName = mapping.getPropertyName(); EntitySetterMethodInfo inf = buildSetterInfo(propertyName); String fieldName = mapping.getTableFieldName(); src.append("entity.").append(inf.getMethodName()).append("("); src.append("rs.").append(resultSetMethod).append("(\"").append( fieldName).append("\")"); src.append(");"); } private void visitPrimitive(StringBuffer src, EntityFieldMapping mapping, Class<?> btAd) { String resultSetMethod = mapping.getDateType().getResultSetMethodName(); String propertyName = mapping.getPropertyName(); EntitySetterMethodInfo inf = buildSetterInfo(propertyName); String fieldName = mapping.getTableFieldName(); // entity.setAge( src.append("entity.").append(inf.getMethodName()).append("("); if (inf.getParameterType() == btAd) { // new Integer( src.append("new ").append(btAd.getName()).append("("); // rs.getInt("age") src.append("rs.").append(resultSetMethod).append("(\"").append( fieldName).append("\")"); // ) src.append(")"); } else { // rs.getInt("age") src.append("rs.").append(resultSetMethod).append("(\"").append( fieldName).append("\")"); } // ); src.append(");"); } protected void visitBlobMethod(StringBuffer src, EntityFieldMapping mapping) { throw new UnsupportedDataType(); } protected void visitClobMethod(StringBuffer src, EntityFieldMapping mapping) { throw new UnsupportedDataType(); } private EntitySetterMethodInfo buildSetterInfo(String propertyName) { String fc = propertyName.substring(0, 1).toUpperCase(); String methodName = "set" + fc + propertyName.substring(1); Method[] ms = entityMapping.getEntityClass().getMethods(); for (Method method : ms) { if (method.getName().equals(methodName)) { Class<?>[] paramType = method.getParameterTypes(); if (paramType.length == 1) { EntitySetterMethodInfo inf = new EntitySetterMethodInfo(); inf.setDesc(Type.getMethodDescriptor(method)); inf.setParameterType(paramType[0]); inf.setMethodName(methodName); return inf; } } } return null; } protected class EntitySetterMethodInfo { private String desc; private Class<?> parameterType; private String methodName; public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public Class<?> getParameterType() { return parameterType; } public void setParameterType(Class<?> parameterType) { this.parameterType = parameterType; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } } } package com.azk.orm; public class ResultSetSupportedDateType { public static final ResultSetSupportedDateType Byte = new ResultSetSupportedDateType( "B", "getByte"); public static final ResultSetSupportedDateType Short = new ResultSetSupportedDateType( "S", "getShort"); public static final ResultSetSupportedDateType Int = new ResultSetSupportedDateType( "I", "getInt"); public static final ResultSetSupportedDateType Long = new ResultSetSupportedDateType( "J", "getLong"); public static final ResultSetSupportedDateType Float = new ResultSetSupportedDateType( "F", "getFloat"); public static final ResultSetSupportedDateType Double = new ResultSetSupportedDateType( "D", "getDoucle"); public static final ResultSetSupportedDateType String = new ResultSetSupportedDateType( "java/lang/String", "getInt"); public static final ResultSetSupportedDateType Date = new ResultSetSupportedDateType( "java/sql/Date", "getInt"); public static final ResultSetSupportedDateType Timestamp = new ResultSetSupportedDateType( "java/sql/Timestamp", "getTimestamp"); public static final ResultSetSupportedDateType BigDecimal = new ResultSetSupportedDateType( "java/math/BigDecimal", "getBigDecimal"); public static final ResultSetSupportedDateType Clob = new ResultSetSupportedDateType( "java/sql/Clob", "getClob"); public static final ResultSetSupportedDateType Blob = new ResultSetSupportedDateType( "java/sql/Blob", "getBlob"); private String typeClassName; private String resultSetMethodName; private ResultSetSupportedDateType(String typeName, String resultSetMethodName) { this.typeClassName = typeName; this.resultSetMethodName = resultSetMethodName; } public String getTypeClassName() { return typeClassName; } public void setTypeClassName(String typeClassName) { this.typeClassName = typeClassName; } public String getResultSetMethodName() { return resultSetMethodName; } public void setResultSetMethodName(String resultSetMethodName) { this.resultSetMethodName = resultSetMethodName; } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |