jmeter java腳本,MyBatis3源碼解析(7)TypeHandler注冊與獲取

 2023-10-12 阅读 31 评论 0

摘要:簡介 在上篇文章中,我們介紹了TypeHandler的簡單使用和解析了TypeHandler的處理核心,這篇文章中我們接著看到TypeHandler是如注冊和獲取使用的 源碼解析 TypeHandler注冊 typeHandler注冊的函數代碼如下: 根據JavaType放入第一層Map根據jdbcType放入第二

簡介

在上篇文章中,我們介紹了TypeHandler的簡單使用和解析了TypeHandler的處理核心,這篇文章中我們接著看到TypeHandler是如注冊和獲取使用的

源碼解析

TypeHandler注冊

typeHandler注冊的函數代碼如下:

  • 根據JavaType放入第一層Map
  • 根據jdbcType放入第二層Map
  configuration.getTypeHandlerRegistry().register(String[].class, JdbcType.VARCHAR, StringArrayTypeHandler.class);private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {if (javaType != null) {Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);if (map == null || map == NULL_TYPE_HANDLER_MAP) {map = new HashMap<>();}map.put(jdbcType, handler);typeHandlerMap.put(javaType, map);}allTypeHandlersMap.put(handler.getClass(), handler);}

TypeHandler獲取

在探索中,我們發現是在Mapper初始化的過程就會去獲取TypeHandler了,在示例代碼中我們調用了函數:addMapper

在該函數中,我們看到了我們熟悉的(前面文章分析過,Sql執行其實就是從Mapper代理類開始的)MapperProxy相關的東西

  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 {// 生成我們熟悉的Mapper代理類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);}}}}

跟蹤下面,我們看到SQLSource生成的相關代碼,ParameterMapper就是從SQLSource帶下去的

  void parseStatement(Method method) {......getAnnotationWrapper(method, true, statementAnnotationTypes).ifPresent(statementAnnotation -> {final SqlSource sqlSource = buildSqlSource(statementAnnotation.getAnnotation(), parameterTypeClass, languageDriver, method);......});}public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {// issue #3if (script.startsWith("<script>")) {XPathParser parser = new XPathParser(script, false, configuration.getVariables(), new XMLMapperEntityResolver());return createSqlSource(configuration, parser.evalNode("/script"), parameterType);} else {// issue #127script = PropertyParser.parse(script, configuration.getVariables());TextSqlNode textSqlNode = new TextSqlNode(script);if (textSqlNode.isDynamic()) {// 這個暫時不理解return new DynamicSqlSource(configuration, textSqlNode);} else {// 目前走的這個return new RawSqlSource(configuration, script, parameterType);}}}public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);String sql;if (configuration.isShrinkWhitespacesInSql()) {sql = parser.parse(removeExtraWhitespaces(originalSql));} else {// 走的這個sql = parser.parse(originalSql);}return new StaticSqlSource(configuration, sql, handler.getParameterMappings());}

jmeter java腳本、下面是對SQL語句進行了解析,最終的效果是遍歷了我們示例SQL中的id和name,對其找到對應的TypeHandler

細節部分沒怎么看到,暫時跳過

public class GenericTokenParser {public String parse(String text) {if (text == null || text.isEmpty()) {return "";}// search open tokenint start = text.indexOf(openToken);if (start == -1) {return text;}char[] src = text.toCharArray();int offset = 0;final StringBuilder builder = new StringBuilder();StringBuilder expression = null;do {if (start > 0 && src[start - 1] == '\\') {// this open token is escaped. remove the backslash and continue.builder.append(src, offset, start - offset - 1).append(openToken);offset = start + openToken.length();} else {// found open token. let's search close token.if (expression == null) {expression = new StringBuilder();} else {expression.setLength(0);}builder.append(src, offset, start - offset);offset = start + openToken.length();int end = text.indexOf(closeToken, offset);while (end > -1) {if (end > offset && src[end - 1] == '\\') {// this close token is escaped. remove the backslash and continue.expression.append(src, offset, end - offset - 1).append(closeToken);offset = end + closeToken.length();end = text.indexOf(closeToken, offset);} else {expression.append(src, offset, end - offset);break;}}if (end == -1) {// close token was not found.builder.append(src, start, src.length - start);offset = src.length;} else {builder.append(handler.handleToken(expression.toString()));offset = end + closeToken.length();}}start = text.indexOf(openToken, offset);} while (start > -1);if (offset < src.length) {builder.append(src, offset, src.length - offset);}return builder.toString();}
}

下面就是根據對應的JavaType和jdbcType,獲取對應的TypeHandler

    public String handleToken(String content) {parameterMappings.add(buildParameterMapping(content));return "?";}// 在其中設置JavaType和jdbcTypeprivate ParameterMapping buildParameterMapping(String content) {Map<String, String> propertiesMap = parseParameterMapping(content);String property = propertiesMap.get("property");Class<?> propertyType;if (metaParameters.hasGetter(property)) { // issue #448 get type from additional paramspropertyType = metaParameters.getGetterType(property);} else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {propertyType = parameterType;} else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {propertyType = java.sql.ResultSet.class;} else if (property == null || Map.class.isAssignableFrom(parameterType)) {propertyType = Object.class;} else {MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());if (metaClass.hasGetter(property)) {propertyType = metaClass.getGetterType(property);} else {propertyType = Object.class;}}ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);Class<?> javaType = propertyType;String typeHandlerAlias = null;for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {String name = entry.getKey();String value = entry.getValue();if ("javaType".equals(name)) {javaType = resolveClass(value);builder.javaType(javaType);} else if ("jdbcType".equals(name)) {builder.jdbcType(resolveJdbcType(value));} else if ("mode".equals(name)) {builder.mode(resolveParameterMode(value));} else if ("numericScale".equals(name)) {builder.numericScale(Integer.valueOf(value));} else if ("resultMap".equals(name)) {builder.resultMapId(value);} else if ("typeHandler".equals(name)) {typeHandlerAlias = value;} else if ("jdbcTypeName".equals(name)) {builder.jdbcTypeName(value);} else if ("property".equals(name)) {// Do Nothing} else if ("expression".equals(name)) {throw new BuilderException("Expression based parameters are not supported yet");} else {throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}.  Valid properties are " + PARAMETER_PROPERTIES);}}if (typeHandlerAlias != null) {builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));}return builder.build();}public ParameterMapping build() {resolveTypeHandler();validate();return parameterMapping;}private void resolveTypeHandler() {if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) {Configuration configuration = parameterMapping.configuration;TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();// 從Map中獲取對應的TypeHandler,以javaType和jdbcType為標識parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);}}private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {if (ParamMap.class.equals(type)) {return null;}// 根據javaType獲取MapMap<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);TypeHandler<?> handler = null;if (jdbcHandlerMap != null) {// 根據jdbcType獲取handler = jdbcHandlerMap.get(jdbcType);if (handler == null) {handler = jdbcHandlerMap.get(null);}if (handler == null) {// #591handler = pickSoleHandler(jdbcHandlerMap);}}// type drives generics herereturn (TypeHandler<T>) handler;}

總結

在本篇文章中,我們初步探索了Mapper初始化的一部分,著重解析了TypeHandler相關的注冊和MapperProxy生成時TypeHandler對應的獲取

核心流程如下:

  • 1.注冊TypeHandler:放入Map中
  • 2.MapperProxy生成,字段的TypeHandler是在SQLSource中,生成SQLSource
  • 3.解析SQL語句,得到對應參數和返回字段的TypeHandler:這部分沒細研究,但后面如果遇到問題,可以回來參考參考
  • 4.根據JavaType和jdbcType得到對應的TypeHandler

這部分還有很多的細節沒來得及去細看,但如果遇到問題,還是能提供方向性的指導

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/135531.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息