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

1.问题描述

在学习mybatis的时候,发现了一个有趣的现象

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

bean类:

sqlmap如下:



测试类代码如下:

@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

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();
  }
}

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

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


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

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

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

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

于是我搜索文本setAccessible(true) 

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

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) 了。


谜底已经解开了。


找到谜底固然欣喜,但解开谜底的过程,更让我学到了不少东西。

对反射的一些类有了更深的认识。

更重要的是 学到在一个复杂 的业务面前 设计是多么的重要啊。



  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值