Analyzed the process from creation to execution of MapperMethod. The execution of MapperMethod includes executing sql and returning results.
The process of executing sql and returning results will involve parameter type conversion, and this process is handled by TypeHandler. About The official website of TypeHandler has a relatively detailed document http://www.mybatis.org/mybatis-3/zh/configuration.html#typeHandlers. The document mainly explains how to use TypeHandler. In the following analysis, the source code related to TypeHandler will be focused on. .
1. Configuration
MyBatis has a default type processor. If you need to customize the configuration, it is quite simple. Add the following configuration to mybatis-config.xml:
<typeHandlers> <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/> </typeHandlers>
The following analyzes the process of configuration reading settings, in XMLConfigBuilder
/** * 读取配置文件组装configuration * @param root 配置文件的configuration节点 */ private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
There is a line
typeHandlerElement(root.evalNode("typeHandlers"));
in the above source code Let’s look at the typeHandlerElement method
/** * 读取typeHandlers配置并注册 * @param parent 配置文件typeHandlers节点 * @throws Exception */ private void typeHandlerElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { String typeHandlerPackage = child.getStringAttribute("name"); typeHandlerRegistry.register(typeHandlerPackage); } else { String javaTypeName = child.getStringAttribute("javaType"); String jdbcTypeName = child.getStringAttribute("jdbcType"); String handlerTypeName = child.getStringAttribute("handler"); Class<?> javaTypeClass = resolveClass(javaTypeName); JdbcType jdbcType = resolveJdbcType(jdbcTypeName); Class<?> typeHandlerClass = resolveClass(handlerTypeName); if (javaTypeClass != null) { if (jdbcType == null) { typeHandlerRegistry.register(javaTypeClass, typeHandlerClass); } else { typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass); } } else { typeHandlerRegistry.register(typeHandlerClass); } } } } }
The code logic in if and else corresponds to the two configuration methods of typeHandler. In the end, it will be called
typeHandlerRegistry.register()
The above is the relationship between TypeHandler and The relationship between TypeHandlerRegistry, Configuration, and BaseTypeHandler.
2. Set parameters
When setting parameters, first call ParameterHandler.setParameters(), then get the corresponding typeHandler in setParameters(), and finally call typeHandler.setParameter()
Let’s take a look at the setParameter method of BaseTypeHandler
When the parameter is not null, setNonNullParameter is called, which means that the subclass needs to implement setNonNullParameter
Source code of BigIntegerTypeHandler:
public void setNonNullParameter(PreparedStatement ps, int i, BigInteger parameter, JdbcType jdbcType) throws SQLException { ps.setBigDecimal(i, new BigDecimal(parameter)); }
At this point, the role of TypeHandler has been roughly analyzed.