博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatis Annotation使用小结
阅读量:6687 次
发布时间:2019-06-25

本文共 4663 字,大约阅读时间需要 15 分钟。

Mybatis Annotation使用小结

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

  1. 先编写一个示例接口

    @Mapper // 标志为 Mybatis 的 Mapperpublic 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依赖

    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    ${mybatis-spring-boot}

    它会自动注入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
    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 
    void addMapper(Class
    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
    (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里面。然而调用过程一致。


代码下载参考

转载于:https://www.cnblogs.com/yaojf/p/7598560.html

你可能感兴趣的文章
经典SQL语句大全
查看>>
测试LCD1602的显示,显示时间,提示语
查看>>
PHP常见的加密技术
查看>>
Asp.net读取AD域信息的方法(一)
查看>>
两道题学习动态规划
查看>>
mysql实战31 | 误删数据后除了跑路,还能怎么办?
查看>>
ASP.NET MVC Razor
查看>>
python:使用OO和工厂模式解决问题
查看>>
C++学习-2
查看>>
GAITC 2019全球人工智能技术大会(南京)
查看>>
使用gradle生成protobuf
查看>>
transition transform animate的使用
查看>>
【翻译】Ext JS最新技巧——2014-5-12
查看>>
全局临时表
查看>>
谈谈加载(Loading)的那点事
查看>>
微信公众平台开发(108) 微信摇一摇
查看>>
linux环境中如何删除文件的前n行?
查看>>
.Net转Java自学之路—SpringMVC框架篇七(Json数据交互)
查看>>
jQuery通过name获取值
查看>>
phpcms网站搬家 至 服务器 完整并且详细过程
查看>>