Mybatis Annotation使用小结

之前一直有看过mybatis的注解使用方式,但没有去看过它的原理。今天看springboot-mybatis-annotation使用的时候,debug了下看了它的加载过程。

  1. 先编写一个示例接口

    @Mapper // 标志为 Mybatis 的 Mapper
    public interface CityDao { /**
    * 根据城市名称,查询城市信息
    *
    * @param cityName 城市名
    */
    @Select("SELECT * FROM city")
    // 返回 Map 结果集
    @Results({
    @Result(property = "id", column = "id"),
    @Result(property = "provinceId", column = "province_id"),
    @Result(property = "cityName", column = "city_name"),
    @Result(property = "description", column = "description"),
    })
    City findByName(@Param("cityName") String cityName);
    }
  2. springboot引入mybatis-spring-boot-starter依赖

    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>${mybatis-spring-boot}</version>
    </dependency>

    它会自动注入MybatisAutoConfiguration这个bean然后解析执行AutoConfiguredMapperScannerRegistrar这个ImportBeanDefinitionRegistrar,它的registerBeanDefinitions方法会扫描包把带有Mapper注解的接口注入到spring容器,并且在内部修改BeanDefinition的class为MapperFactoryBean,并且设置它的自动注入模式为AUTOWIRE_BY_TYPE,实现了SqlSessionFactory的自动注入。

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { logger.debug("Searching for mappers annotated with @Mapper"); ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); try {
    if (this.resourceLoader != null) {
    scanner.setResourceLoader(this.resourceLoader);
    } List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
    if (logger.isDebugEnabled()) {
    for (String pkg : packages) {
    logger.debug("Using auto-configuration base package '{}'", pkg);
    }
    } scanner.setAnnotationClass(Mapper.class);
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(packages));
    } catch (IllegalStateException ex) {
    logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
    }
    }
  3. MapperFactoryBean的实例化

    MapperFactoryBean继承了SqlSessionDaoSupport,SqlSessionDaoSupport继承了DaoSupport,DaoSupport它实现了InitializingBean,所以实例化MapperFactoryBean的时候会调用afterPropertiesSet方法。
    	   @Override
    public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
    // Let abstract subclasses check their configuration.
    checkDaoConfig(); // Let concrete implementations initialize themselves.
    try {
    initDao();
    }
    catch (Exception ex) {
    throw new BeanInitializationException("Initialization of DAO failed", ex);
    }
    }

    这里会调用MapperFactoryBean的重写方法checkDaoConfig

      protected void checkDaoConfig() {
    super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration();
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
    try {
    configuration.addMapper(this.mapperInterface);
    } catch (Exception e) {
    logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
    throw new IllegalArgumentException(e);
    } finally {
    ErrorContext.instance().reset();
    }
    }
    }
	  因为配置了方法注解所以我们在不配置xml的时候configuration里并没有对应的mapperRegistry,所以会调用configuration的addMapper方法,内部会调用mapperRegistry的addMapper方法

	```
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
``` 从以上代码可知通过MapperAnnotationBuilder这个类去解析当前接口的方法上的配置信息转化成MappedStatement并设置到全局的Configuration里面。这样就和直接解析xml配置达到了一样的效果。 4. MapperFactoryBean生成的动态代理bean的调用 MapperFactoryBean生成的动态代理bean,调用方法的过程最终会委派给MapperProxy的invoke方法,后续的调用过程就和xml解析出来的配置一致了,也就是说不管是注解配置还是xml配置只是解析配置的方式不同,最终都会设置到Configuration里面。然而调用过程一致。 ---
代码下载参考[springboot-learning-example](https://github.com/yaojf/springboot-learning-example)

Mybatis Annotation使用小结的更多相关文章

  1. Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司需要人.产品.业务和方向,方向又要人.产品.业务和方向,方向… 循环』 本文提纲一. ...

  2. MyBatis之级联小结

    在这之前我们知道了MyBatis为我们提供了三种级联:一对一关系(assocation).一对多关系(collection).鉴别器(discriminator).在最后一个鉴别器例子中,看到了当层级 ...

  3. MyBatis动态SQL小结

    6:用于实现动态sql的元素及其用法 if+set--完成更新操作 if+where --完成多条件查询 if+完成多条件查询(替代where)或完成更新操作(替代set) choose(when,o ...

  4. SQL mybatis动态查询小结

    动态返回mysql某张表指定列的名字 <select id="queryColumns" resultType="map" parameterType=& ...

  5. 【mybatis annotation】数据层框架应用--Mybatis(二) 基于注解实现数据的CRUD

    使用MyBatis框架进行持久层开发 MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架. MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索. MyBa ...

  6. MyBatis注解Annotation介绍及Demo

     MyBatis注解Annotation介绍及Demo 2014-04-21 17:09:55 标签:Mybatis Annotation 注解 ResultMap SqlBuilder 原创作品,允 ...

  7. MyBatis Tutorial – CRUD Operations and Mapping Relationships – Part 1---- reference

    http://www.javacodegeeks.com/2012/11/mybatis-tutorial-crud-operations-and-mapping-relationships-part ...

  8. mybatis通用DAO

    扫扫关注"茶爸爸"微信公众号 坚持最初的执着,从不曾有半点懈怠,为优秀而努力,为证明自己而活. 回复:茶爸爸了解他这个人!! 花了几天的时间研究了一下mybatis的源代码,觉得这 ...

  9. MyBatis浅尝笔记

    MyBatis应属于一种轻量级的java持久层技术,它通过简单的SQL xml或注解,将数据库数据映射到接口与POJO.最近项目要用到mybatis,所以学习之后在这里做个总结,文中的示例以xml配置 ...

随机推荐

  1. input按钮使用方法

  2. 爬虫 requests 模块

    requests 模块 介绍 使用requests可以模拟浏览器的请求, 比起之前用到的urllib,requests模块的api更加便捷(本质就是封装了urllib3) ps: requests库发 ...

  3. edusoho -A5: ApiBundle UML

    edusoho -A5:  ApiBundle UML

  4. ubuntu16.04连接wifi

    前提:实验室里没有网线,也没有无线网络,只能用个人手机开热点上网! Then~~ 首先参考了这两篇博文: https://blog.csdn.net/weixin_41762173/article/d ...

  5. centos7搭建gitlab服务器、汉化

    1.下载rpm安装包 https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-8.8.5-ce.1.el7.x86_64.rp ...

  6. postgres 基本操作

    登陆: $ psql -U <user> -d <dbname> 数据库操作: $ \l      //查看库 $  \c <dbname>   //切换库 // ...

  7. 实战Google深度学习框架-C3-TensorFlow入门

    第三章:TensorFlow入门 TensorFlow存在计算模型,数据模型和运算模型(本文用TF代表TensorFlow) 3.1 计算模型-计算图 3.1.1 计算图的概念 TensorFlow这 ...

  8. CAS server打包小白教程

    如题,cas是耶鲁大学的一个开源的登录系统,功能齐全,受到很多企业的青睐. 耶鲁大学都不知道那你太out了,我告诉你吧!耶鲁大学就是山东一个椰子树长的很多的地方的大学,很牛逼. 很多新手程序员简历都喜 ...

  9. docker的安装与基本使用

    安装docker curl -s https://get.docker.com|sh 好慢....一个小时吧... 启动docker 先执行命令docker version来来一下: docker v ...

  10. 微星X470主板装机

    记录一下装机过程,以作纪念 配置 机箱:先马黑洞3 电源:先马金牌500w CPU:AMD 锐龙5:2600X 主板:微星 X470 暗黑版 显卡:七彩虹 RTX2060 内存:科赋 3200,2条8 ...