在MapperRegistry.addMapper时会用到MapperAnnotationBuilder。

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<>(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);}}}}

1、类结构

2、解析

2.1 解析缓存

缓存注解定义

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CacheNamespace {Class<? extends Cache> implementation() default PerpetualCache.class;Class<? extends Cache> eviction() default LruCache.class;long flushInterval() default 0;int size() default 1024;boolean readWrite() default true;boolean blocking() default false;Property[] properties() default {};
}

获取注解@CacheNamespace,得到缓存大小,缓存刷新间隔,缓存其他属性,缓存实现类,缓存淘汰策略,缓存读写,缓存是否阻塞。添加到configuration中。

private void parseCache() {CacheNamespace cacheDomain = type.getAnnotation(CacheNamespace.class);if (cacheDomain != null) {Integer size = cacheDomain.size() == 0 ? null : cacheDomain.size();Long flushInterval = cacheDomain.flushInterval() == 0 ? null : cacheDomain.flushInterval();Properties props = convertToProperties(cacheDomain.properties());assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), flushInterval, size, cacheDomain.readWrite(), cacheDomain.blocking(), props);}}

2.2 解析缓存引用

缓存引用注解为CacheNamespaceRef,其定义为

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CacheNamespaceRef {Class<?> value() default void.class;String name() default "";
}

获取注解的引用类型及引用名称(两个当中只能有一个配置),如果引用类型不为void.class,使用类型的getName,否则使用配置的refName作为名字空间。

private void parseCacheRef() {CacheNamespaceRef cacheDomainRef = type.getAnnotation(CacheNamespaceRef.class);if (cacheDomainRef != null) {Class<?> refType = cacheDomainRef.value();String refName = cacheDomainRef.name();if (refType == void.class && refName.isEmpty()) {throw new BuilderException("Should be specified either value() or name() attribute in the @CacheNamespaceRef");}if (refType != void.class && !refName.isEmpty()) {throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef");}String namespace = (refType != void.class) ? refType.getName() : refName;try {assistant.useCacheRef(namespace);} catch (IncompleteElementException e) {configuration.addIncompleteCacheRef(new CacheRefResolver(assistant, namespace));}}}

2.3 解析结果映射

迭代类型的方法,如果方法有注解@Select或者@SelectProvider,没有注解@ResultMap时,解析结果映射。

Select注解定义为

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(Select.List.class)
public @interface Select {String[] value();String databaseId() default "";@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@interface List {Select[] value();}
}

SelectProvider注解定义为

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(SelectProvider.List.class)
public @interface SelectProvider {Class<?> value() default void.class;Class<?> type() default void.class;String method() default "";String databaseId() default "";@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@interface List {SelectProvider[] value();}
}

ResultMap注解定义为

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResultMap {String[] value();
}

获取方法上的@Arg,@Result,@TypeDiscriminator注解,通过@Result注解生成ResultMap名,如果@Result的id不为空,使用类型名+id作为映射名。否则根据方法名的参数类型生成映射名

private String generateResultMapName(Method method) {Results results = method.getAnnotation(Results.class);if (results != null && !results.id().isEmpty()) {return type.getName() + "." + results.id();}StringBuilder suffix = new StringBuilder();for (Class<?> c : method.getParameterTypes()) {suffix.append("-");suffix.append(c.getSimpleName());}if (suffix.length() < 1) {suffix.append("-void");}return type.getName() + "." + method.getName() + suffix;}

通过@Arg注解生成构造映射

private void applyConstructorArgs(Arg[] args, Class<?> resultType, List<ResultMapping> resultMappings) {for (Arg arg : args) {List<ResultFlag> flags = new ArrayList<>();flags.add(ResultFlag.CONSTRUCTOR);if (arg.id()) {flags.add(ResultFlag.ID);}@SuppressWarnings("unchecked")Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)(arg.typeHandler() == UnknownTypeHandler.class ? null : arg.typeHandler());ResultMapping resultMapping = assistant.buildResultMapping(resultType,nullOrEmpty(arg.name()),nullOrEmpty(arg.column()),arg.javaType() == void.class ? null : arg.javaType(),arg.jdbcType() == JdbcType.UNDEFINED ? null : arg.jdbcType(),nullOrEmpty(arg.select()),nullOrEmpty(arg.resultMap()),null,nullOrEmpty(arg.columnPrefix()),typeHandler,flags,null,null,false);resultMappings.add(resultMapping);}}

通过@Result注解构造映射

private void applyResults(Result[] results, Class<?> resultType, List<ResultMapping> resultMappings) {for (Result result : results) {List<ResultFlag> flags = new ArrayList<>();if (result.id()) {flags.add(ResultFlag.ID);}@SuppressWarnings("unchecked")Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)((result.typeHandler() == UnknownTypeHandler.class) ? null : result.typeHandler());boolean hasNestedResultMap = hasNestedResultMap(result);ResultMapping resultMapping = assistant.buildResultMapping(resultType,nullOrEmpty(result.property()),nullOrEmpty(result.column()),result.javaType() == void.class ? null : result.javaType(),result.jdbcType() == JdbcType.UNDEFINED ? null : result.jdbcType(),hasNestedSelect(result) ? nestedSelectId(result) : null,hasNestedResultMap ? nestedResultMapId(result) : null,null,hasNestedResultMap ? findColumnPrefix(result) : null,typeHandler,flags,null,null,isLazy(result));resultMappings.add(resultMapping);}}

解析@TypeDiscriminator注解构造discriminator

private Discriminator applyDiscriminator(String resultMapId, Class<?> resultType, TypeDiscriminator discriminator) {if (discriminator != null) {String column = discriminator.column();Class<?> javaType = discriminator.javaType() == void.class ? String.class : discriminator.javaType();JdbcType jdbcType = discriminator.jdbcType() == JdbcType.UNDEFINED ? null : discriminator.jdbcType();@SuppressWarnings("unchecked")Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)(discriminator.typeHandler() == UnknownTypeHandler.class ? null : discriminator.typeHandler());Case[] cases = discriminator.cases();Map<String, String> discriminatorMap = new HashMap<>();for (Case c : cases) {String value = c.value();String caseResultMapId = resultMapId + "-" + value;discriminatorMap.put(value, caseResultMapId);}return assistant.buildDiscriminator(resultType, column, javaType, jdbcType, typeHandler, discriminatorMap);}return null;}

最后创建ResultMap

private void applyResultMap(String resultMapId, Class<?> returnType, Arg[] args, Result[] results, TypeDiscriminator discriminator) {List<ResultMapping> resultMappings = new ArrayList<>();applyConstructorArgs(args, returnType, resultMappings);applyResults(results, returnType, resultMappings);Discriminator disc = applyDiscriminator(resultMapId, returnType, discriminator);// TODO add AutoMappingBehaviourassistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null);createDiscriminatorResultMaps(resultMapId, returnType, discriminator);}

2.4 解析语句

解析方法上的@Select,@Update,@Insert,@Delete,@SelectProvider,@UpdateProvider,@InsertProvider,@DeleteProvider注解,同时获取方法上的@Options注解,如果语句类型是insert,update语句,获取@SelectKey注解,对于select语句,获取@ResultMap注解,最后添加语句到configuration中。

void parseStatement(Method method) {final Class<?> parameterTypeClass = getParameterType(method);final LanguageDriver languageDriver = getLanguageDriver(method);getAnnotationWrapper(method, true, statementAnnotationTypes).ifPresent(statementAnnotation -> {final SqlSource sqlSource = buildSqlSource(statementAnnotation.getAnnotation(), parameterTypeClass, languageDriver, method);final SqlCommandType sqlCommandType = statementAnnotation.getSqlCommandType();final Options options = getAnnotationWrapper(method, false, Options.class).map(x -> (Options)x.getAnnotation()).orElse(null);final String mappedStatementId = type.getName() + "." + method.getName();final KeyGenerator keyGenerator;String keyProperty = null;String keyColumn = null;if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {// first check for SelectKey annotation - that overrides everything elseSelectKey selectKey = getAnnotationWrapper(method, false, SelectKey.class).map(x -> (SelectKey)x.getAnnotation()).orElse(null);if (selectKey != null) {keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);keyProperty = selectKey.keyProperty();} else if (options == null) {keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;} else {keyGenerator = options.useGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;keyProperty = options.keyProperty();keyColumn = options.keyColumn();}} else {keyGenerator = NoKeyGenerator.INSTANCE;}Integer fetchSize = null;Integer timeout = null;StatementType statementType = StatementType.PREPARED;ResultSetType resultSetType = configuration.getDefaultResultSetType();boolean isSelect = sqlCommandType == SqlCommandType.SELECT;boolean flushCache = !isSelect;boolean useCache = isSelect;if (options != null) {if (FlushCachePolicy.TRUE.equals(options.flushCache())) {flushCache = true;} else if (FlushCachePolicy.FALSE.equals(options.flushCache())) {flushCache = false;}useCache = options.useCache();fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348timeout = options.timeout() > -1 ? options.timeout() : null;statementType = options.statementType();if (options.resultSetType() != ResultSetType.DEFAULT) {resultSetType = options.resultSetType();}}String resultMapId = null;if (isSelect) {ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);if (resultMapAnnotation != null) {resultMapId = String.join(",", resultMapAnnotation.value());} else {resultMapId = generateResultMapName(method);}}assistant.addMappedStatement(mappedStatementId,sqlSource,statementType,sqlCommandType,fetchSize,timeout,// ParameterMapIDnull,parameterTypeClass,resultMapId,getReturnType(method),resultSetType,flushCache,useCache,// TODO gcode issue #577false,keyGenerator,keyProperty,keyColumn,statementAnnotation.getDatabaseId(),languageDriver,// ResultSetsoptions != null ? nullOrEmpty(options.resultSets()) : null);});}

mybatis中的MapperAnnotationBuilder相关推荐

  1. if mybatis tk 多个_面试题:mybatis 中的 DAO 接口和 XML 文件里的 SQL 是如何建立关系的?...

    前言 这是 mybatis 比较常问到的面试题,我自己在以前的面试过程中被问到了2次,2次都是非常重要的面试环节,因此自己印象很深刻. 这个题目我很早就深入学习了,但是一直没有整理出来,刚好最近一段时 ...

  2. mybatis与php,浅谈mybatis中的#和$的区别

    浅谈mybatis中的#和$的区别 发布于 2016-07-30 11:14:47 | 236 次阅读 | 评论: 0 | 来源: 网友投递 MyBatis 基于Java的持久层框架MyBatis 本 ...

  3. MyBatis中#{}和${}的区别

    ------------------------siwuxie095 MyBatis 中 #{} 和 ${} 的区别 1.在 MyBatis 的映射配置文件中,动态传递参数有两种方式: (1)#{} ...

  4. Mybatis中Oracle和Mysql的Count字段问题

    Mybatis中Oracle和Mysql的Count字段问题 我们在进行项目开发时经常会碰到查询总数的问题,所以我们直接是用select count(1) from table来进行查询.那么在Myb ...

  5. MyBatis中jdbcType=INTEGER、VARCHAR作用

    Mapper.xml中 pid = #{pid,jdbcType=INTEGER} pid = #{pid} 都可以用 Mybatis中什么时候应该声明jdbcType? 当Mybatis不能自动识别 ...

  6. Mybatis 中$与#的区别

    1 #是将传入的值当做字符串的形式,eg:select id,name,age from student where id =#{id},当前端把id值1,传入到后台的时候,就相当于 select i ...

  7. MyBatis中使用流式查询避免数据量过大导致OOM

    欢迎关注方志朋的博客,回复"666"获面试宝典 今天mybatis查询数据库中大量的数据,程序抛出: java.lang.OutOfMemoryError: Java heap s ...

  8. 解决MyBatis中 Could not set property ~ o f ~异常

    解决MyBatis中 Could not set property ~ of ~ public class Role {private Integer id; //idprivate String r ...

  9. 复习下mybatis 中 useGeneratedKeys 和 keyProperty 含义

    今天突然碰到这个错误,让我复习下mybatis 中 useGeneratedKeys 和 keyProperty 含义 nested exception is org.apache.ibatis.ex ...

最新文章

  1. Python django实现简单的邮件系统发送邮件功能
  2. 汤家凤高等数学2020年强化笔记-第三模块-积分学
  3. php算出文件相对路径,php计算两个文件相对路径的方法
  4. SQL SERVER大话存储结构(2)
  5. Linux部署动态网页,Nginx发布支持动态配置的开源Web服务器
  6. PCL:PCL可视化显示点云
  7. session和cookie的最深刻理解
  8. LeetCode 561. Array Partition I
  9. 猜拳游戏php中Computer类,人机猜拳 (玩家、电脑、游戏、测试)四个类写法
  10. 启动tomcat后无法访问
  11. AI学习笔记(七)图像滤波器、OpenCV算法解析
  12. SQL使用技巧(转)
  13. 面向太阳,不问春暖花开
  14. IDEA连接服务器执行python程序
  15. axios封装接口步骤详解
  16. linux 命令下载jdk
  17. 处女作《Web全栈开发进阶之路》出版了!
  18. conan-transit服上的库列表
  19. H5案例分享:微信视频播放全屏问题
  20. 「查看电量」Apple Watch的4种查看电量方法

热门文章

  1. linux内核编译及系统裁减
  2. jQuery 1.9+ ajaxStart事件无效,无法被触发的原因。
  3. 创建数据源(ODBC)
  4. C#各种小知识点总结
  5. ExtJS ComboBox 异步读取项后默认选中某项
  6. python有趣代码-Python有哪些有趣的代码呢,这些代码让
  7. python装饰器作用-Python装饰器详解
  8. python官网地址-python官网网址
  9. python27-python27安装
  10. python工作招聘-爬了招聘网站之后,给你几点学习Python的建议