Previous:
MapperMethod of mybatis source code analysis
https://my.oschina.net/u/657390/blog/755787
The process of MapperMethod from creation to execution is analyzed, and the execution of MapperMethod includes executing sql to return results.
The conversion of parameter types is involved in the process of executing sql and returning results. This process is handled by TypeHandler. There are more detailed documents on the official website of TypeHandler 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 analyzed.
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 configuring read 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);
}
}
In the above source code there is a line
typeHandlerElement(root.evalNode("typeHandlers"));
Let's look at the method of typeHandlerElement
/**
* 读取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 TypeHandlerRegistry, Configuration, 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, that is to say, 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));
}
So far, the role of TypeHandler has been roughly analyzed.