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. 11.2 Flask 配置文件,路由系统

    配置文件系统 构建 Flask 应用时指定 app = Flask( __name__, template_folder = '', # 指定存储模板文件夹名称 static_url_path = ' ...

  2. hdu 2829 Lawrence(四边形不等式优化dp)

    T. E. Lawrence was a controversial figure during World War I. He was a British officer who served in ...

  3. 使用item来封装数据:

    一.item和field类: 1.使用Item类: 创建了类Bookitem,然后就可以使用: 2.item_pipeline: 我们可以使用item_pipeline对爬取的数据进行处理. 步骤: ...

  4. 洛谷P1776 宝物筛选

    一道很好的单调队列优化多重背包入门题 令\(v[i]\)表示重量,\(w[i]\)表示价格 ,\(c[i]\)表示最多可放的数量,不难推出朴素的转移方程如下: \(f[i][j]=max\{f[i-1 ...

  5. Vue(小案例_vue+axios仿手机app)_go实现退回上一个路由

    一.前言 this.$router.go(-1)返回上级路由 二.主要内容 1.小功能演示: 2.组件之间的嵌套关系为: 3.具体实现 (1)由于这种返回按钮在每个页面中的结构都是一样的,只是里面的数 ...

  6. Luogu_2015 二叉苹果树

    题目链接 SB 裸题……就是想随便挂在这里……同样的题还有 Luogu_2014 选课. Luogu_2015 二叉苹果树 #include <queue> #include <cs ...

  7. PowerShell Empire使用笔记

    ##安装过程 git clone https://github.com/EmpireProject/Empire.git cd Empire cd setup sudo ./install.sh ## ...

  8. 深入剖析Kubernetes学习笔记:开篇词(00)

    一.关于Kubernetes初学的疑惑 就在这场因"容器"而起的技术变革中,kubernetes项目已经成为容器技术的事实标准,重新定义了基础设置领域对应用编排与管理的种种可能 1 ...

  9. DirectX11 With Windows SDK--19 模型加载:obj格式的读取及使用二进制文件提升读取效率

    前言 一个模型通常是由三个部分组成:网格.纹理.材质.在一开始的时候,我们是通过Geometry类来生成简单几何体的网格.但现在我们需要寻找合适的方式去表述一个复杂的网格,而且包含网格的文件类型多种多 ...

  10. Silverlight/WPF 系列汇总

    Silverlight 解谜游戏系列 -- Silverlight 3 · Silverlight 解谜游戏 之一 新建项目 · Silverlight 解谜游戏 之二 创建题板 · Silverli ...