mybatis中的MapperAnnotationBuilder
在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相关推荐
- if mybatis tk 多个_面试题:mybatis 中的 DAO 接口和 XML 文件里的 SQL 是如何建立关系的?...
前言 这是 mybatis 比较常问到的面试题,我自己在以前的面试过程中被问到了2次,2次都是非常重要的面试环节,因此自己印象很深刻. 这个题目我很早就深入学习了,但是一直没有整理出来,刚好最近一段时 ...
- mybatis与php,浅谈mybatis中的#和$的区别
浅谈mybatis中的#和$的区别 发布于 2016-07-30 11:14:47 | 236 次阅读 | 评论: 0 | 来源: 网友投递 MyBatis 基于Java的持久层框架MyBatis 本 ...
- MyBatis中#{}和${}的区别
------------------------siwuxie095 MyBatis 中 #{} 和 ${} 的区别 1.在 MyBatis 的映射配置文件中,动态传递参数有两种方式: (1)#{} ...
- Mybatis中Oracle和Mysql的Count字段问题
Mybatis中Oracle和Mysql的Count字段问题 我们在进行项目开发时经常会碰到查询总数的问题,所以我们直接是用select count(1) from table来进行查询.那么在Myb ...
- MyBatis中jdbcType=INTEGER、VARCHAR作用
Mapper.xml中 pid = #{pid,jdbcType=INTEGER} pid = #{pid} 都可以用 Mybatis中什么时候应该声明jdbcType? 当Mybatis不能自动识别 ...
- Mybatis 中$与#的区别
1 #是将传入的值当做字符串的形式,eg:select id,name,age from student where id =#{id},当前端把id值1,传入到后台的时候,就相当于 select i ...
- MyBatis中使用流式查询避免数据量过大导致OOM
欢迎关注方志朋的博客,回复"666"获面试宝典 今天mybatis查询数据库中大量的数据,程序抛出: java.lang.OutOfMemoryError: Java heap s ...
- 解决MyBatis中 Could not set property ~ o f ~异常
解决MyBatis中 Could not set property ~ of ~ public class Role {private Integer id; //idprivate String r ...
- 复习下mybatis 中 useGeneratedKeys 和 keyProperty 含义
今天突然碰到这个错误,让我复习下mybatis 中 useGeneratedKeys 和 keyProperty 含义 nested exception is org.apache.ibatis.ex ...
最新文章
- Python django实现简单的邮件系统发送邮件功能
- 汤家凤高等数学2020年强化笔记-第三模块-积分学
- php算出文件相对路径,php计算两个文件相对路径的方法
- SQL SERVER大话存储结构(2)
- Linux部署动态网页,Nginx发布支持动态配置的开源Web服务器
- PCL:PCL可视化显示点云
- session和cookie的最深刻理解
- LeetCode 561. Array Partition I
- 猜拳游戏php中Computer类,人机猜拳 (玩家、电脑、游戏、测试)四个类写法
- 启动tomcat后无法访问
- AI学习笔记(七)图像滤波器、OpenCV算法解析
- SQL使用技巧(转)
- 面向太阳,不问春暖花开
- IDEA连接服务器执行python程序
- axios封装接口步骤详解
- linux 命令下载jdk
- 处女作《Web全栈开发进阶之路》出版了!
- conan-transit服上的库列表
- H5案例分享:微信视频播放全屏问题
- 「查看电量」Apple Watch的4种查看电量方法