您的位置:首页 > 其它

关于Mybatis的研究之 bean没有set方法 也可以赋值

2018-02-01 23:20 459 查看
在学习mybatis的时候,发现了一个有趣的现象

如果resultType所指向的bean没有set方法时 在ibatis上是不能成功并且报错误 但在mybatis却是可以的

bean类:



sqlmap如下:



测试类代码如下:

[java] view
plain copy

@Test  

    public void testNewTable() throws IOException{  

        String resource = "sqlMap_config.xml";  

        Reader reader = Resources.getResourceAsReader(resource);  

        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();  

        SqlSessionFactory factory = builder.build(reader);  

          

        SqlSession session = factory.openSession();  

        List<User> list = session.selectList("NewTable.selectAll");  

          

        System.out.println( list.get(0) );  

          

    }  

这样User类的属性居然是有值的!!!!

这着实让我很诧异 在排除了是我操作的问题的情况下,最终的造成此现象的根源在于mybatis本身。

于是我有了想看mybatis源码的冲动。。。。

2.分析问题

说实话,这是我第一次正儿八经的看框架源码。

一个字:杂啊!!!

但杂而不乱,我debug了好久才找到了根源

类SetFieldInvoke

[java] view
plain copy

public class SetFieldInvoker implements Invoker {  

  private Field field;  

  

  public SetFieldInvoker(Field field) {  

    this.field = field;  

  }  

  

  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {  

    field.set(target, args[0]);  

    return null;  

  }  

  

  public Class<?> getType() {  

    return field.getType();  

  }  

}  

[java] view
plain copy

field.set(target, args[0]);  

原来它利用的是反射原理直接操作属性而非set方法

但有一个问题出现了 User类中的属性都是private的。如果 Field 类中没有setAccessible(true)的话,是不会访问到私有属性的。

在SetFieldInvoke方法中并没有执行此方法啊,但结果确实是给私有属性赋值了。

可以说明一点是setAccessible(true)此方法 肯定是执行了。

剩下的问题是此方法在哪里执行了??

于是我搜索文本setAccessible(true) 

果然在org.apache.ibatis.reflection.Reflector 中 发现了此方法在调用

[java] view
plain copy

private void addFields(Class<?> clazz) {  

    Field[] fields = clazz.getDeclaredFields();  

    for (Field field : fields) {  

      if (canAccessPrivateMethods()) {  

        try {  

          field.setAccessible(true);  

        } catch (Exception e) {  

          // Ignored. This is only a final precaution, nothing we can do.  

        }  

      }  

      if (field.isAccessible()) {  

        if (!setMethods.containsKey(field.getName())) {  

          // issue 379 - removed the check for final because JDK 1.5 allows  

          // modification of final fields through reflection (JSR-133).  (JGB)  

          addSetField(field);  

        }  

        if (!getMethods.containsKey(field.getName())) {  

          addGetField(field);  

        }  

      }  

    }  

    if (clazz.getSuperclass() != null) {  

      addFields(clazz.getSuperclass());  

    }  

  }  

简单来说,就是在初始化的时候就将每个属性都setAccessible(true)了

说明一点就是mybaits 的result结果集的映射用的是暴力反射 直接赋值;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐