Mybatis对象生成与属性赋值-反射技术

Mybatis对象生成与属性赋值-反射技术

反射模块 工具类
1、org.apache.ibatis.reflection.factory.ObjectFactory 生成原始类
2、org.apache.ibatis.reflection.ReflectorFactory --反射模块基础****,生成Reflector类:对class信息的封装,获得元数据
实体类可以没有get set方法,都可以设置值
3、org.apache.ibatis.reflection.wrapper.ObjectWrapper 主要功能为类赋值,私有方法获得没有set方法也能赋值
4、org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory
5、org.apache.ibatis.reflection.MetaObject 向外界提供的开放接口

代码跟踪

以 selectList 方法调用为例分析返回值对象的生成

方法最终调用到

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet

  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        if (resultHandler == null) {
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
//这里是入口
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      closeResultSet(rsw.getResultSet());
    }
  }

 

我们先分析最简单的分支,即

if (resultHandler == null) {
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
//这里是入口
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          multipleResults.add(defaultResultHandler.getResultList());
        }

这个分支,实例化了一个 DefaultResultHandler 来处理查询结果;

继续跟代码:

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValues
↓
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap
↓
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.lang.String)
↓
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createResultObject(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, org.apache.ibatis.executor.loader.ResultLoaderMap, java.lang.String)

到这一步就可以看到返回值实例化的过程了,

return objectFactory.create(resultType);即 DefaultObjectFactory 的instantiateClass 方法;最终是找到指定类的构造方法,执行  return constructor.newInstance();

这里只是把要返回的对象做了实例化,下一步是将属性设置对应的值,就用到了 MetaObject 这一套api

代码回到 getRowValue:

  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
//这里是核心
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }

下面跟几个MataObject的简单使用例子,赋值原理一样

MetaObject

POJO

设计一个没有set 但是有get方法的类

package com.uu;

public class Man {

  private String name;

  public String getName() {
    return name;
  }
}

调用MataObject方法设置属性的值

  @Test
  public void testMetaObject(){
    Man man = new Man();
    MetaObject metaObject = MetaObject.forObject(man, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
    metaObject.setValue("name","999");
    System.out.println(man.getName());
  }

打印的结果是:999

Collection

  @Test
  public void testCollection(){
    Man man = new Man();
    man.setName("kanan");

    List<Man> list = new ArrayList<>();
    MetaObject metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
    metaObject.add(man);
    System.out.println(list.get(0).getName());
  }

打印结果是:kanan

Map

  @Test
  public void testMap(){
    Man man = new Man();
    man.setName("kanan");

    Map<String,Man> map = new HashMap<>();
    MetaObject metaObject = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
    metaObject.setValue("m",man);
    System.out.println(map.get("m").getName());
  }

打印结果是:kanan

内在乾坤

我们看看 MetaObject.forObject 方法的调用堆栈

  private void addFields(Class<?> clazz) {
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      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)
        // pr #16 - final static can only be set by the classloader
        int modifiers = field.getModifiers();
        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
          addSetField(field);
        }
      }
      if (!getMethods.containsKey(field.getName())) {
        addGetField(field);
      }
    }
    if (clazz.getSuperclass() != null) {
      addFields(clazz.getSuperclass());
    }
  }

这个方法主要功能是通过反射获得当前pojo类的 Field 集合,再分别封装成 SetFieldInvoker和 GetFieldInvoker放在不同的map里;

在调用org.apache.ibatis.reflection.MetaObject#setValue api时主要逻辑是根据方法名称找到对应的SetFieldInvoker,便找到了对应的Field(以BeanWrapper为例子):

org.apache.ibatis.reflection.wrapper.BeanWrapper#set
↓
org.apache.ibatis.reflection.wrapper.BeanWrapper#setBeanProperty
↓
//找到对应的Field并调用set方法
org.apache.ibatis.reflection.invoker.SetFieldInvoker#invoke
  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException {
    try {
      field.set(target, args[0]);
    } catch (IllegalAccessException e) {
//异常时设置Field的可见性
      if (Reflector.canControlMemberAccessible()) {
        field.setAccessible(true);
        field.set(target, args[0]);
      } else {
        throw e;
      }
    }
    return null;
  }

这样真正的值就被设置进入属性了

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值