文主要解答一个问题,即如果bean没有setter,而且属性不是public的,mybatis的自动组装是否可以赋值成功的问题。

查询调用过程

DefaultSqlSession.selectList -->SimpleExecutor.doQuery --> SimpleStatementHandler.query --> DefaultResultSetHandler.handleResultSets --> BeanWrapper.setBeanProperty --> MetaClass.getSetInvoker --> Reflector.getSetInvoker

关键方法

SimpleStatementHandler.query

  1. public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  2. String sql = boundSql.getSql();
  3. statement.execute(sql);
  4. return resultSetHandler.<E>handleResultSets(statement);
  5. }

DefaultResultSetHandler.handleResultSets

  1. @Override
  2. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  3. ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  4. final List<Object> multipleResults = new ArrayList<Object>();
  5. int resultSetCount = 0;
  6. ResultSetWrapper rsw = getFirstResultSet(stmt);
  7. List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  8. int resultMapCount = resultMaps.size();
  9. validateResultMapsCount(rsw, resultMapCount);
  10. while (rsw != null && resultMapCount > resultSetCount) {
  11. ResultMap resultMap = resultMaps.get(resultSetCount);
  12. handleResultSet(rsw, resultMap, multipleResults, null);
  13. rsw = getNextResultSet(stmt);
  14. cleanUpAfterHandlingResultSet();
  15. resultSetCount++;
  16. }
  17. String[] resultSets = mappedStatement.getResulSets();
  18. if (resultSets != null) {
  19. while (rsw != null && resultSetCount < resultSets.length) {
  20. ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  21. if (parentMapping != null) {
  22. String nestedResultMapId = parentMapping.getNestedResultMapId();
  23. ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  24. handleResultSet(rsw, resultMap, null, parentMapping);
  25. }
  26. rsw = getNextResultSet(stmt);
  27. cleanUpAfterHandlingResultSet();
  28. resultSetCount++;
  29. }
  30. }
  31. return collapseSingleResultList(multipleResults);
  32. }

DefaultResultSetHandler.handleResultSets

  1. private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
  2. try {
  3. if (parentMapping != null) {
  4. handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
  5. } else {
  6. if (resultHandler == null) {
  7. DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
  8. handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
  9. multipleResults.add(defaultResultHandler.getResultList());
  10. } else {
  11. handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
  12. }
  13. }
  14. } finally {
  15. // issue #228 (close resultsets)
  16. closeResultSet(rsw.getResultSet());
  17. }
  18. }

DefaultResultSetHandler.handleRowValues

  1. private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  2. if (resultMap.hasNestedResultMaps()) {
  3. ensureNoRowBounds();
  4. checkResultHandler();
  5. handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  6. } else {
  7. handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  8. }
  9. }

DefaultResultSetHandler.handleRowValuesForSimpleResultMap

  1. private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
  2. throws SQLException {
  3. DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
  4. skipRows(rsw.getResultSet(), rowBounds);
  5. while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
  6. ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
  7. Object rowValue = getRowValue(rsw, discriminatedResultMap);
  8. storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
  9. }
  10. }

DefaultResultSetHandler.getRowValue

  1. private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
  2. final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  3. Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
  4. if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
  5. final MetaObject metaObject = configuration.newMetaObject(resultObject);
  6. boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
  7. if (shouldApplyAutomaticMappings(resultMap, false)) {
  8. foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
  9. }
  10. foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
  11. foundValues = lazyLoader.size() > 0 || foundValues;
  12. resultObject = foundValues ? resultObject : null;
  13. return resultObject;
  14. }
  15. return resultObject;
  16. }

DefaultResultSetHandler.applyPropertyMappings

  1. private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
  2. throws SQLException {
  3. final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
  4. boolean foundValues = false;
  5. final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
  6. for (ResultMapping propertyMapping : propertyMappings) {
  7. String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
  8. if (propertyMapping.getNestedResultMapId() != null) {
  9. // the user added a column attribute to a nested result map, ignore it
  10. column = null;
  11. }
  12. if (propertyMapping.isCompositeResult()
  13. || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
  14. || propertyMapping.getResultSet() != null) {
  15. Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
  16. // issue #541 make property optional
  17. final String property = propertyMapping.getProperty();
  18. // issue #377, call setter on nulls
  19. if (value != DEFERED
  20. && property != null
  21. && (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()))) {
  22. metaObject.setValue(property, value);
  23. }
  24. if (value != null || value == DEFERED) {
  25. foundValues = true;
  26. }
  27. }
  28. }
  29. return foundValues;
  30. }

MetaObject.setValue

  1. public void setValue(String name, Object value) {
  2. PropertyTokenizer prop = new PropertyTokenizer(name);
  3. if (prop.hasNext()) {
  4. MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
  5. if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
  6. if (value == null && prop.getChildren() != null) {
  7. // don't instantiate child path if value is null
  8. return;
  9. } else {
  10. metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
  11. }
  12. }
  13. metaValue.setValue(prop.getChildren(), value);
  14. } else {
  15. objectWrapper.set(prop, value);
  16. }
  17. }

BeanWrapper.set

  1. @Override
  2. public void set(PropertyTokenizer prop, Object value) {
  3. if (prop.getIndex() != null) {
  4. Object collection = resolveCollection(prop, object);
  5. setCollectionValue(prop, collection, value);
  6. } else {
  7. setBeanProperty(prop, object, value);
  8. }
  9. }

BeanWrapper.setBeanProperty

  1. private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
  2. try {
  3. Invoker method = metaClass.getSetInvoker(prop.getName());
  4. Object[] params = {value};
  5. try {
  6. method.invoke(object, params);
  7. } catch (Throwable t) {
  8. throw ExceptionUtil.unwrapThrowable(t);
  9. }
  10. } catch (Throwable t) {
  11. throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
  12. }
  13. }

MetaClass.getSetInovker

  1. public Invoker getSetInvoker(String name) {
  2. return reflector.getSetInvoker(name);
  3. }

Reflector.getSetInvoker

  1. public Invoker getSetInvoker(String propertyName) {
  2. Invoker method = setMethods.get(propertyName);
  3. if (method == null) {
  4. throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
  5. }
  6. return method;
  7. }

setMethods的修改

有setter的话,走Reflector. resolveSetterConflicts

  1. private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
  2. for (String propName : conflictingSetters.keySet()) {
  3. List<Method> setters = conflictingSetters.get(propName);
  4. Method firstMethod = setters.get(0);
  5. if (setters.size() == 1) {
  6. addSetMethod(propName, firstMethod);
  7. } else {
  8. Class<?> expectedType = getTypes.get(propName);
  9. if (expectedType == null) {
  10. throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
  11. + propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " +
  12. "specification and can cause unpredicatble results.");
  13. } else {
  14. Iterator<Method> methods = setters.iterator();
  15. Method setter = null;
  16. while (methods.hasNext()) {
  17. Method method = methods.next();
  18. if (method.getParameterTypes().length == 1
  19. && expectedType.equals(method.getParameterTypes()[0])) {
  20. setter = method;
  21. break;
  22. }
  23. }
  24. if (setter == null) {
  25. throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
  26. + propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " +
  27. "specification and can cause unpredicatble results.");
  28. }
  29. addSetMethod(propName, setter);
  30. }
  31. }
  32. }
  33. }
  34. private void addSetMethod(String name, Method method) {
  35. if (isValidPropertyName(name)) {
  36. setMethods.put(name, new MethodInvoker(method));
  37. setTypes.put(name, method.getParameterTypes()[0]);
  38. }
  39. }

没有setter的话,走Reflector. addSetField

  1. private void addSetField(Field field) {
  2. if (isValidPropertyName(field.getName())) {
  3. setMethods.put(field.getName(), new SetFieldInvoker(field));
  4. setTypes.put(field.getName(), field.getType());
  5. }
  6. }

小结

即使bean的属性是私有的,没有setter,mybatis也会通过反射去设置值。

mybatis结果的组装(springboot)的更多相关文章

  1. 普通spring jsp+mybatis项目修改为springboot + jsp +mybatis项目

    概述 由于公司决定使用spring cloud,但是公司积累了大量的普通的jsp项目,老的项目直接全部修改为springboot成本过高,周期比较长,而且公司业务正在快速拓展,所以需要把之前的老项目修 ...

  2. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

  3. springBoot和MyBatis整合中出现SpringBoot无法启动时处理方式

    在springBoot和Myatis   整合中出现springBoot无法启动   并且报以下错误 Description: Field userMapper in cn.lijun.control ...

  4. springboot mybatis 事务管理

    本文主要讲述springboot提供的声明式的事务管理机制. 一.一些概念 声明式的事务管理是基于AOP的,在springboot中可以通过@Transactional注解的方式获得支持,这种方式的优 ...

  5. springboot+mybatis+ehcache实现缓存数据

    一.springboot缓存简介 在 Spring Boot中,通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),Spring Boot根据下面的顺序去侦测缓 ...

  6. Springboot 系列(十一)使用 Mybatis(自动生成插件) 访问数据库

    1. Springboot mybatis 介绍 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数获取 ...

  7. springboot集成下,mybatis的mapper代理对象究竟是如何生成的

    前言 开心一刻 中韩两学生辩论. 中:端午节是属于谁的? 韩:韩国人! 中:汉字是谁发明的? 韩:韩国人! 中:中医是属于谁的? 韩:韩国人! 中:那中国人到底发明过什么? 韩:韩国人! 前情回顾 M ...

  8. 零基础IDEA整合SpringBoot + Mybatis项目,及常见问题详细解答

    开发环境介绍:IDEA + maven + springboot2.1.4 1.用IDEA搭建SpringBoot项目:File - New - Project - Spring Initializr ...

  9. springboot学习四:整合mybatis

    在application.properties加入配置 ## Mybatis 配置 mybatis.typeAliasesPackage=org.spring.springboot.domain my ...

随机推荐

  1. BZOJ 1212 [HNOI2004]L语言 【AC自动机 + 背包】

    题目链接[http://www.lydsy.com/JudgeOnline/problem.php?id=1212] 题意:给你一些单词,然后给出一个没有标点的文本串S,都是小写字符.现在让你求用给出 ...

  2. luoguP4571 [JSOI2009]瓶子和燃料 裴蜀定理

    裴蜀定理的扩展 最后返回的一定是\(k\)个数的\(gcd\) 因此对于每个数暴力分解因子统计即可 #include <map> #include <cstdio> #incl ...

  3. VC 操作 EXCEL---插入工作表(Insert.Sheet)方法

    看到的资料 http://bbs.csdn.net/topics/198565 自己总结一下 //插入到nIndex工作表之前 void InsertSheet(int nIndex) { sheet ...

  4. SCSI Pass-Through Interface Tool

    http://code.msdn.microsoft.com/SCSI-Pass-Through-a906ceef/sourcecode?fileId=59048&pathId=1919073 ...

  5. HTTP 协议中 Vary 的一些研究

    经常抓包看 HTTP 请求的同学应该对 Vary 这个响应头字段并不陌生,它有什么用?用 PageSpeed 工具检查页面时,经常看到「Specify a Vary: Accept-Encoding ...

  6. android软件中加入广告实现方法

    经过了一番折腾,忙忙碌碌了一下午,终于搞明白了Android软件界面嵌入广告的方法,以下我以嵌入有米广告为例小结一下: 步骤一,下载有米广告SDK,将 youmi-android.jar 导入想要嵌入 ...

  7. Oracle约束的启用和停用

      关于Oracle的约束概念和基本操作,我已经在以前的<Constraint基础概念>.<Constraint的简单操作>两篇文章中有过比较详细的介绍了,但是对于如何停用和启 ...

  8. 使用依赖关系注入在 ASP.NET Core 中编写干净代码

    ASP.NET Core 1.0 是 ASP.NET 的完全重新编写,这个新框架的主要目标之一就是更多的模块化设计.即,应用应该能够仅利用其所需的框架部分,方法是框架在它们请求时提供依赖关系.此外,使 ...

  9. Android定制争夺战 三大主流ROM横评

    随着MIUI在广大“机油”们心目中位置的逐渐攀升,越来越多的厂商也相继推出了属于自己的定制Android ROM,想以此来抢占这一新兴市场,像点心OS.腾讯的Tita以及近期比较热门的百度云ROM等等 ...

  10. 常见的Hadoop十大应用误解

    常见的Hadoop十大应用误解 1.        (误解) Hadoop什么都可以做 (正解) 当一个新技术出来时,我们都会去思考它在各个不同产业的应用,而对于平台的新技术来说,我们思考之后常会出现 ...