Java 如何加速反射代码?
在我的应用程序中,我使用Apache的DBUtils类从MySQL数据库中读取数据。我编写了一个定制的BasicRowProcessor,它使用数据对象字段上的注释从数据库中读取列。它在代码方面工作得非常好,但是当我拉很多行时,性能相当慢。例如,使用此代码,1500行x35列的结果集需要800毫秒,但如果使用标准JDBC代码,则只需要80毫秒 问题-我可以做些什么来加速此代码?具体地说,我使用了大量的反射和注释——是否有我遗漏的加快速度的技巧Java 如何加速反射代码?,java,performance,reflection,Java,Performance,Reflection,在我的应用程序中,我使用Apache的DBUtils类从MySQL数据库中读取数据。我编写了一个定制的BasicRowProcessor,它使用数据对象字段上的注释从数据库中读取列。它在代码方面工作得非常好,但是当我拉很多行时,性能相当慢。例如,使用此代码,1500行x35列的结果集需要800毫秒,但如果使用标准JDBC代码,则只需要80毫秒 问题-我可以做些什么来加速此代码?具体地说,我使用了大量的反射和注释——是否有我遗漏的加快速度的技巧 @Override public <T
@Override
public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException
{
T data = type.newInstance();
Field[] f = type.getFields();
for (int i=0; i<f.length; i++)
{
Field field = f[i];
if (field.isAnnotationPresent(DBColumn.class))
{
String columnName = field.getAnnotation(DBColumn.class).name();
}
if (field.getType().getName().equals("int"))
{
field.setInt(data, rs.getInt(columnName));
}
else if (field.getType().getName().equals("long"))
{
field.setLong(data, rs.getLong(columnName));
}
// .... for all the other types
}
return data;
}
@覆盖
公共T toBean(结果集rs,类类型)引发SQLException
{
T data=type.newInstance();
字段[]f=type.getFields();
对于(int i=0;i不比较类型的名称。将类型与int.class、long.class等进行比较
事实上,您不需要所有这些“if”语句。只需调用Field.set(),使用ResultSet.getObject()作为参数。所有正确的事情都会在内部发生。但我不认为这会更快
您最好使用java.beans内省器的反射功能,因为它会为您缓存所有反射内容。也许可以构建并缓存行映射逻辑,这样您就不必每次都扫描字段、注释、结果集元数据和类型
JDBC元数据访问特别慢
在本例中,您可以提供一个字符串“key”,以便为不同的结果集类型(不同的列结构)启用映射器的高效缓存
public BasicRowProcessor GetReflectVerowMapper(结果集rs,字符串结果集键,类类型){
字符串键=resultSetKey+“-”+类型;
BasicRowProcessor result=rrmCache.get(键);
如果(结果!=null){
结果=BuildReflectVerowMapper(rs、resultSetKey、类型);
rrmCache.put(键、结果);
}
返回结果;
}
公共BuiltRowProcessor BuildReflectVerowMapper(结果集rs,字符串结果集键,类类型){
}
然后
public class BuiltRowProcessor extends BasicRowProcessor {
protected FieldMapping[] mappings;
@Override
public <T> T toBean (ResultSet rs, Class<T> type) throws SQLException {
T data = type.newInstance();
for (FieldMapping field : mappings) {
field.mapField( rs, data);
}
return data;
}
}
abstract public class FieldMapping {
protected Field field;
protected int columnIndex;
// constructor..
abstract public void mapField (ResultSet rs, Object target) throws SQLException;
protected void writeField (Object target, Object value) {
try {
field.setValue(target, value); // or whatever API.
} catch (Exception x) {
throw new RuntimeException("error writing field: "+field, x);
}
}
}
public IntMapping extends FieldMapping {
// constructor..
public void mapField (ResultSet rs, Object target) throws SQLException {
int value = rs.getInt(columnIndex);
writeField( target, value);
}
}
公共类BuiltRowProcessor扩展了基本处理器{
受保护的字段映射[]映射;
@凌驾
公共T toBean(结果集rs,类类型)引发SQLException{
T data=type.newInstance();
for(字段映射字段:映射){
字段.映射字段(rs,数据);
}
返回数据;
}
}
抽象公共类字段映射{
保护地;
受保护的int列索引;
//建造师。。
抽象公共void映射字段(ResultSet rs,Object target)抛出SQLException;
受保护的void writeField(对象目标、对象值){
试一试{
field.setValue(target,value);//或任何API。
}捕获(异常x){
抛出新的RuntimeException(“错误写入字段:”+字段,x);
}
}
}
公共IntMapping扩展了FieldMapping{
//建造师。。
公共void映射字段(结果集rs,对象目标)引发SQLException{
int值=rs.getInt(columnIndex);
writeField(目标、值);
}
}
如果你的代码有效,你应该改为发布到。提示一:不要使用反射。你为什么要这样做而不是使用现有的JPA实现?@antoh,但它没有,它太慢了。而且CR已经死了(或者还没有出生),你不能期望在那里得到任何答案。@maaartinus对我来说,太慢是一个有效的代码,但没有我想要的那么快,根据它的页面,这就是CR的用途。而且,如果没有人使用它,它永远不会起飞:)难道Class
和Method
不也做内部缓存吗?@SotiriosDelimanolis我想是的。在某些情况下,自己的缓存会阻止一些JIT优化(我可能是错的)。在函数上运行一些度量,是否将类型与int.Class进行比较或将type.getShortName()与“int”进行比较并不重要。这些都同样快。真正慢的代码在注释检索函数isAnnotationPresent()和getAnnotation()中。75%的函数时间在这两行代码中。
public class BuiltRowProcessor extends BasicRowProcessor {
protected FieldMapping[] mappings;
@Override
public <T> T toBean (ResultSet rs, Class<T> type) throws SQLException {
T data = type.newInstance();
for (FieldMapping field : mappings) {
field.mapField( rs, data);
}
return data;
}
}
abstract public class FieldMapping {
protected Field field;
protected int columnIndex;
// constructor..
abstract public void mapField (ResultSet rs, Object target) throws SQLException;
protected void writeField (Object target, Object value) {
try {
field.setValue(target, value); // or whatever API.
} catch (Exception x) {
throw new RuntimeException("error writing field: "+field, x);
}
}
}
public IntMapping extends FieldMapping {
// constructor..
public void mapField (ResultSet rs, Object target) throws SQLException {
int value = rs.getInt(columnIndex);
writeField( target, value);
}
}