Mybatis是我们日常开发过程中经常使用的ORM框架,读者可以首先参考Mybatis中文官方文档来看一下Mybatis的使用示例,首先要通过SqlSessionFactoryBuilder来构建SqlSessionFactory,我们就以SqlSessionFactory的构建为入口来分析Mybatis源码:
SqlSessionFactoryBuilder:
public SqlSessionFactory build(InputStream inputStream) {
/* 构建SqlSessionFactory */
return build(inputStream, null, null);
}
SqlSessionFactoryBuilder:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
/* 解析配置,构建SqlSessionFactory */
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
}
}
}
XMLConfigBuilder:
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
/* 解析配置 */
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
关于配置的功能及使用方法,请参考官方文档,地址已经给出。
XMLConfigBuilder:
private void parseConfiguration(XNode root) {
try {
/* 解析properties标签 */
propertiesElement(root.evalNode("properties"));
/* 解析settings标签 */
Properties settings = settingsAsProperties(root.evalNode("settings"));
/* 设置自定义VFS */
loadCustomVfs(settings);
/* 解析typeAliases标签 */
typeAliasesElement(root.evalNode("typeAliases"));
/* 解析plugins标签 */
pluginElement(root.evalNode("plugins"));
/* 解析objectFactory标签 */
objectFactoryElement(root.evalNode("objectFactory"));
/* 解析objectWrapperFactory标签 */
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
/* 解析reflectorFactory标签 */
reflectorFactoryElement(root.evalNode("reflectorFactory"));
/* 将settings配置放入configuration对象中 */
settingsElement(settings);
/* 解析environments标签 */
environmentsElement(root.evalNode("environments"));
/* 解析databaseIdProvider标签 */
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
/* 解析typeHandlers标签 */
typeHandlerElement(root.evalNode("typeHandlers"));
/* 解析mappers标签 */
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
XMLConfigBuilder:
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties defaults = context.getChildrenAsProperties();
// 获取resource属性
String resource = context.getStringAttribute("resource");
// 获取url属性
String url = context.getStringAttribute("url");
// 两者不能同时存在
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
if (resource != null) {
// 如果resource不为空则加载resource配置的配置文件
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
// 如果url不为空则加载url配置的资源
defaults.putAll(Resources.getUrlAsProperties(url));
}
Properties vars = configuration.getVariables();
if (vars != null) {
// 如果定义了configuration对象的变量同样加入配置中
defaults.putAll(vars);
}
// 将配置放入parser和configuration对象中
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
XMLConfigBuilder:
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties props = context.getChildrenAsProperties();
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
// 校验Configuration类中是否有对应的setter方法
for (Object key : props.keySet()) {
if (!metaConfig.hasSetter(String.valueOf(key))) {
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
return props;
}
XMLConfigBuilder:
private void loadCustomVfs(Properties props) throws ClassNotFoundException {
// 将用户自定义VFS放入configuration对象中
String value = props.getProperty("vfsImpl");
if (value != null) {
String[] clazzes = value.split(",");
for (String clazz : clazzes) {
if (!clazz.isEmpty()) {
@SuppressWarnings("unchecked")
Class<? extends VFS> vfsImpl = (Class<? extends VFS>)Resources.classForName(clazz);
configuration.setVfsImpl(vfsImpl);
}
}
}
}
这里提到了Mybatis VFS,简单介绍一下,它提供一个非常简单的API,用于访问应用程序服务器内的资源。
XMLConfigBuilder:
private void typeAliasesElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
/* 指定包名的类别名注册 */
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
/* 没有指定别名的类别名注册 */
typeAliasRegistry.registerAlias(clazz);
} else {
/* 指定别名的类别名注册 */
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
TypeAliasRegistry:
public void registerAliases(String packageName){
/* 根据包名注册类别名 */
registerAliases(packageName, Object.class);
}
TypeAliasRegistry:
public void registerAliases(String packageName, Class<?> superType){
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
// 加载包下面的类
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for(Class<?> type : typeSet){
// 非匿名类,非接口类,非成员类
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
/* 注册类别名 */
registerAlias(type);
}
}
}
TypeAliasRegistry:
public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
// 如果注解了@Alias,则取注解的值作为别名
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
/* 注册类别名 */
registerAlias(alias, type);
}
TypeAliasRegistry:
public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// 别名转成小写
String key = alias.toLowerCase(Locale.ENGLISH);
// 如果已经包含当前别名,并且不为null,并且新值和原来的值不一样,抛出异常
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
// 将键值映射关系放入别名映射中
TYPE_ALIASES.put(key, value);
}
TypeAliasRegistry:
public void registerAlias(String alias, String value) {
try {
// 在指定别名的情况下同样也是调用上面的方法进行注册
registerAlias(alias, Resources.classForName(value));
} catch (ClassNotFoundException e) {
throw new TypeException("Error registering type alias "+alias+" for "+value+". Cause: " + e, e);
}
}
Mybatis默认为我们注册了很多别名,在构造TypeAliasRegistry对象时:
public TypeAliasRegistry() {
registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
registerAlias("ResultSet", ResultSet.class);
}
在构造Configuration对象时:
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
这些别名我们都是可以直接使用的。
XMLConfigBuilder:
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
// 获取interceptor属性配置的类名或者类别名
String interceptor = child.getStringAttribute("interceptor");
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties properties = child.getChildrenAsProperties();
// 反射实例化
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
// 为拦截器设置用户指定的property配置
interceptorInstance.setProperties(properties);
// 将拦截器添加到configuration对象中
configuration.addInterceptor(interceptorInstance);
}
}
}
XMLConfigBuilder:
private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
// 获取type属性配置的类名或者类别名
String type = context.getStringAttribute("type");
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties properties = context.getChildrenAsProperties();
// 反射实例化
ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
// 为ObjectFactory设置用户指定的property配置
factory.setProperties(properties);
// 将ObjectFactory设置到configuration对象中
configuration.setObjectFactory(factory);
}
}
XMLConfigBuilder:
private void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
// 获取type属性配置的类名或者类别名
String type = context.getStringAttribute("type");
// 反射实例化
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
// 将ObjectWrapperFactory设置到configuration对象中
configuration.setObjectWrapperFactory(factory);
}
}
XMLConfigBuilder:
private void reflectorFactoryElement(XNode context) throws Exception {
if (context != null) {
// 获取type属性配置的类名或者类别名
String type = context.getStringAttribute("type");
// 反射实例化
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
// 将ReflectorFactory设置到configuration对象中
configuration.setReflectorFactory(factory);
}
}
XMLConfigBuilder:
private void settingsElement(Properties props) throws Exception {
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
@SuppressWarnings("unchecked")
Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
configuration.setLogImpl(logImpl);
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
}
这里就是将settings对应的配置设置到configuration对象中。
XMLConfigBuilder:
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
// 获取environment默认配置id
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
// 获取子标签environment的id属性
String id = child.getStringAttribute("id");
// 判断与默认配置id是否相同
if (isSpecifiedEnvironment(id)) {
/* 解析transactionManager子标签 */
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
/* 解析dataSource子标签 */
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
// 构建Environment对象并设置到configuration对象中
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
XMLConfigBuilder:
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
// 获取type属性配置的类名或者类别名
String type = context.getStringAttribute("type");
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties props = context.getChildrenAsProperties();
// 反射实例化
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
// 为TransactionFactory设置用户指定的property配置
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
XMLConfigBuilder:
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
// 获取type属性配置的类名或者类别名
String type = context.getStringAttribute("type");
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties props = context.getChildrenAsProperties();
// 反射实例化
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
// 为DataSourceFactory设置用户指定的property配置
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
XMLConfigBuilder:
private void databaseIdProviderElement(XNode context) throws Exception {
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
// 获取type属性配置的类名或者类别名
String type = context.getStringAttribute("type");
if ("VENDOR".equals(type)) {
// 这里的DB_VENDOR类别名是在构造Configuration对象时注册的,对应的类是VendorDatabaseIdProvider
type = "DB_VENDOR";
}
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties properties = context.getChildrenAsProperties();
// 反射实例化
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
// 为DatabaseIdProvider设置用户指定的property配置
databaseIdProvider.setProperties(properties);
}
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
// 获取databaseId
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
configuration.setDatabaseId(databaseId); // 设置到configuration对象中
}
}
XMLConfigBuilder:
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");
// 获取javaType属性配置的类名或者类别名
Class<?> javaTypeClass = resolveClass(javaTypeName);
// 根据jdbcType配置的名称在枚举找到对应的枚举值
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
// 获取handler属性配置的类名或者类别名
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
if (javaTypeClass != null) {
if (jdbcType == null) {
/* 注册类型处理器 */
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
/* 注册类型处理器 */
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
/* 注册类型处理器 */
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
TypeHandlerRegistry:
public void register(String packageName) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
// 加载包下面的类
resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
for (Class<?> type : handlerSet) {
// 非匿名类,非接口类,非abstract修饰的类
if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
register(type); /* 注册类型处理器 */
}
}
}
TypeHandlerRegistry:
public void register(Class<?> typeHandlerClass) {
boolean mappedTypeFound = false;
MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
// 如果注解了@MappedTypes,则使用注解属性值作为javaType
if (mappedTypes != null) {
for (Class<?> javaTypeClass : mappedTypes.value()) {
/* 注册类型处理器 */
register(javaTypeClass, typeHandlerClass);
mappedTypeFound = true;
}
}
if (!mappedTypeFound) {
/* 获取TypeHandler实例,注册类型处理器 */
register(getInstance(null, typeHandlerClass));
}
}
TypeHandlerRegistry:
public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
/* 获取TypeHandler实例,注册类型处理器 */
register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
}
TypeHandlerRegistry:
public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
if (javaTypeClass != null) {
try {
// 如果有javaType,则将javaType作为参数实例化类型处理器
Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
return (TypeHandler<T>) c.newInstance(javaTypeClass);
} catch (NoSuchMethodException ignored) {
} catch (Exception e) {
throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
}
}
try {
// 无参构造方法实例化类型处理器
Constructor<?> c = typeHandlerClass.getConstructor();
return (TypeHandler<T>) c.newInstance();
} catch (Exception e) {
throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
}
}
TypeHandlerRegistry:
private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
// 获取类型处理器上的@MappedJdbcTypes注解信息
MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
if (mappedJdbcTypes != null) {
for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
/* 遍历注解的value属性配置的JdbcType数组作为jdbcType注册类型处理器 */
register(javaType, handledJdbcType, typeHandler);
}
if (mappedJdbcTypes.includeNullJdbcType()) {
/* 如果注解配置了允许包括null值的jdbcType则注册jdbcType为null的类型处理器 */
register(javaType, null, typeHandler);
}
} else {
/* 注册jdbcType为null的类型处理器 */
register(javaType, null, typeHandler);
}
}
TypeHandlerRegistry:
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
if (javaType != null) {
Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
if (map == null) {
map = new HashMap<JdbcType, TypeHandler<?>>();
TYPE_HANDLER_MAP.put(javaType, map);
}
map.put(jdbcType, handler);
}
ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
}
注册的过程就是将对应jdbcType、javaType、typeHandler三者的对应关系存入映射中。另外几个重载的注册类型处理器的方法都大同小异,就不做赘述了,另外在构造TypeHandlerRegistry时,Mybatis注册一些默认的类型处理器:
public TypeHandlerRegistry() {
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
try {
register("java.time.Instant", "org.apache.ibatis.type.InstantTypeHandler");
register("java.time.LocalDateTime", "org.apache.ibatis.type.LocalDateTimeTypeHandler");
register("java.time.LocalDate", "org.apache.ibatis.type.LocalDateTypeHandler");
register("java.time.LocalTime", "org.apache.ibatis.type.LocalTimeTypeHandler");
register("java.time.OffsetDateTime", "org.apache.ibatis.type.OffsetDateTimeTypeHandler");
register("java.time.OffsetTime", "org.apache.ibatis.type.OffsetTimeTypeHandler");
register("java.time.ZonedDateTime", "org.apache.ibatis.type.ZonedDateTimeTypeHandler");
register("java.time.Month", "org.apache.ibatis.type.MonthTypeHandler");
register("java.time.Year", "org.apache.ibatis.type.YearTypeHandler");
register("java.time.YearMonth", "org.apache.ibatis.type.YearMonthTypeHandler");
register("java.time.chrono.JapaneseDate", "org.apache.ibatis.type.JapaneseDateTypeHandler");
} catch (ClassNotFoundException e) {
}
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
}
配置文件解析的最后一步就是对mapper配置的解析:
XMLConfigBuilder:
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
/* 按照包名配置解析 */
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
/* 按照resource配置解析 */
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
/* 按照url配置解析 */
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
/* 按照class配置解析 */
configuration.addMapper(mapperInterface);
} else {
// 三者只能出现一个,某则抛出异常
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
Configuration:
public void addMappers(String packageName) {
/* 根据包名注册mapper */
mapperRegistry.addMappers(packageName);
}
MapperRegistry:
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
// 加载包下面的类
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
/* 添加mapper */
addMapper(mapperClass);
}
}
MapperRegistry:
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) { // mapper类必须是接口
if (hasMapper(type)) { // 如果mapper已经存在,报错
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type)); // 将当前mapper添加到已知mapper集合中
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse(); /* 解析mapper配置 */
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type); // 如果解析出现异常,从已知的mapper集合中移除掉当前mapper
}
}
}
}
MapperAnnotationBuilder:
public void parse() {
String resource = type.toString();
// 判断是否已经加载过,防止重复加载
if (!configuration.isResourceLoaded(resource)) {
loadXmlResource(); /* 加载xml配置 */
configuration.addLoadedResource(resource); // 标记为已经加载的资源
assistant.setCurrentNamespace(type.getName());
parseCache(); /* 解析@CacheNamespace注解配置 */
parseCacheRef(); /* 解析@CacheNamespaceRef注解配置 */
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
if (!method.isBridge()) {
parseStatement(method); /* 解析方法上的注解配置 */
}
} catch (IncompleteElementException e) {
// 添加到未完成解析的方法解析器集合中,后续继续解析
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
parsePendingMethods(); // 解析挂起的方法
}
MapperAnnotationBuilder:
private void loadXmlResource() {
// 判断是否已经加载过,防止重复加载
if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
// 将类名的.替换成/,也就是查找当前路径下同名的xml文件作为配置文件
String xmlResource = type.getName().replace('.', '/') + ".xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
} catch (IOException e) {
}
if (inputStream != null) {
XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
/* 解析xml配置 */
xmlParser.parse();
}
}
}
public void parse() {
// 判断是否已经加载过,防止重复加载
if (!configuration.isResourceLoaded(resource)) {
/* 解析mapper配置 */
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource); // 标记为已加载资源
bindMapperForNamespace(); /* 为命名空间绑定mapper */
}
parsePendingResultMaps(); // 解析挂起的resultMap
parsePendingCacheRefs(); // 解析挂起的cacheRef
parsePendingStatements(); // 解析挂起的statement
}
这里提到了对挂起元素的解析,什么时候会有挂起元素后面会详细说明,对挂起元素的解析和正常解析的流程是一样的,就是从configuration对象中拿出挂起的元素再次解析一遍。
XMLMapperBuilder:
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace"); // 获取命名空间配置
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
// 设置当前命名空间
builderAssistant.setCurrentNamespace(namespace);
/* 标签解析 */
cacheRefElement(context.evalNode("cache-ref"));
/* 标签解析 */
cacheElement(context.evalNode("cache"));
// 标签解析,目前已经废弃这个用法
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
/* 标签解析 */
resultMapElements(context.evalNodes("/mapper/resultMap"));
/* 标签解析 */
sqlElement(context.evalNodes("/mapper/sql"));
/* 、 、 、 标签解析 */
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
XMLMapperBuilder:
private void cacheRefElement(XNode context) {
if (context != null) {
// 将当前命名空间和cache-ref中配置的命名空间添加映射关系
configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
try {
// 这里的解析主要是验证cache-ref关联的缓存对象是否已经存在,如果不存在,就会抛出IncompleteElementException异常
cacheRefResolver.resolveCacheRef();
} catch (IncompleteElementException e) {
// 添加到未完成解析的cache-ref集合中,后续继续解析
configuration.addIncompleteCacheRef(cacheRefResolver);
}
}
}
XMLMapperBuilder:
private void cacheElement(XNode context) throws Exception {
if (context != null) {
// 获取缓存类型配置,默认为PERPETUAL持久化缓存,支持实现Cache接口自定义缓存
String type = context.getStringAttribute("type", "PERPETUAL");
// 获取类名或类别名对应的Class对象
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
// 获取回收策略配置,默认为LRU最近最少使用原则
String eviction = context.getStringAttribute("eviction", "LRU");
// 获取类名或类别名对应的Class对象,Mybatis提供的几种的回收策略在构建Configuration对象时注册了别名,上文介绍过
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
// 获取flushInterval缓存刷新间隔配置,默认没有刷新间隔
Long flushInterval = context.getLongAttribute("flushInterval");
// 获取size缓存引用数目配置,默认值是1024
Integer size = context.getIntAttribute("size");
// 获取缓存只读属性配置
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
// 获取缓存blocking配置
boolean blocking = context.getBooleanAttribute("blocking", false);
// 将子标签的name和value属性作为键值对放入Properties对象中
Properties props = context.getChildrenAsProperties();
/* 添加缓存 */
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
MapperBuilderAssistant:
public Cache useNewCache(Class<? extends Cache> typeClass,
Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
/* 构建缓存 */
Cache cache = new CacheBuilder(currentNamespace)
.implementation(valueOrDefault(typeClass, PerpetualCache.class))
.addDecorator(valueOrDefault(evictionClass, LruCache.class))
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
// 添加到缓存映射中
configuration.addCache(cache);
currentCache = cache;
return cache;
}
CacheBuilder:
public Cache build() {
// 设置默认实现,如果没有默认实现会用PerpetualCache作为默认实现并添加默认装饰者LruCache
setDefaultImplementations();
// 反射实例化cache,id也就是命名空间会作为构造方法的参数
Cache cache = newBaseCacheInstance(implementation, id);
/* 为缓存设置用户自定义属性 */
setCacheProperties(cache);
if (PerpetualCache.class.equals(cache.getClass())) {
for (Class<? extends Cache> decorator : decorators) {
// 装饰者装饰缓存对象,默认就是LruCache装饰PerpetualCache
cache = newCacheDecoratorInstance(decorator, cache);
/* 装饰者装饰之后再次为缓存对象设置用户自定义属性 */
setCacheProperties(cache);
}
/* 设置基本的装饰者 */
cache = setStandardDecorators(cache);
} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
// 如果基本cache对象不是PerpetualCache并且没有继承LoggingCache,那么用LoggingCache装饰基本cache对象,主要是为了记录缓存命中比例
cache = new LoggingCache(cache);
}
return cache;
}
CacheBuilder:
private void setCacheProperties(Cache cache) {
if (properties != null) {
MetaObject metaCache = SystemMetaObject.forObject(cache);
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String name = (String) entry.getKey();
String value = (String) entry.getValue();
// 根据配置找到相关setter方法调用赋值
if (metaCache.hasSetter(name)) {
Class<?> type = metaCache.getSetterType(name);
if (String.class == type) {
metaCache.setValue(name, value);
} else if (int.class == type
|| Integer.class == type) {
metaCache.setValue(name, Integer.valueOf(value));
} else if (long.class == type
|| Long.class == type) {
metaCache.setValue(name, Long.valueOf(value));
} else if (short.class == type
|| Short.class == type) {
metaCache.setValue(name, Short.valueOf(value));
} else if (byte.class == type
|| Byte.class == type) {
metaCache.setValue(name, Byte.valueOf(value));
} else if (float.class == type
|| Float.class == type) {
metaCache.setValue(name, Float.valueOf(value));
} else if (boolean.class == type
|| Boolean.class == type) {
metaCache.setValue(name, Boolean.valueOf(value));
} else if (double.class == type
|| Double.class == type) {
metaCache.setValue(name, Double.valueOf(value));
} else {
throw new CacheException("Unsupported property type for cache: '" + name + "' of type " + type);
}
}
}
}
// 如果cache对象实现了InitializingObject接口,在这里调用它的initialize方法
if (InitializingObject.class.isAssignableFrom(cache.getClass())){
try {
((InitializingObject) cache).initialize();
} catch (Exception e) {
throw new CacheException("Failed cache initialization for '" +
cache.getId() + "' on '" + cache.getClass().getName() + "'", e);
}
}
}
CacheBuilder:
private Cache setStandardDecorators(Cache cache) {
try {
MetaObject metaCache = SystemMetaObject.forObject(cache);
if (size != null && metaCache.hasSetter("size")) {
metaCache.setValue("size", size);
}
if (clearInterval != null) {
// 如果配置了flushInterval,则用ScheduledCache装饰基本cache对象
cache = new ScheduledCache(cache);
((ScheduledCache) cache).setClearInterval(clearInterval);
}
if (readWrite) {
// 如果配置了readOnly为true,则用SerializedCache装饰基本cache对象
cache = new SerializedCache(cache);
}
// 用LoggingCache装饰基本cache对象
cache = new LoggingCache(cache);
// 用SynchronizedCache装饰基本cache对象
cache = new SynchronizedCache(cache);
// 如果配置了blocking为true,则用BlockingCache装饰基本cache对象
if (blocking) {
cache = new BlockingCache(cache);
}
return cache;
} catch (Exception e) {
throw new CacheException("Error building standard cache decorators. Cause: " + e, e);
}
}
XMLMapperBuilder:
private void resultMapElements(List<XNode> list) throws Exception {
for (XNode resultMapNode : list) {
try {
/* 解析 标签 */
resultMapElement(resultMapNode);
} catch (IncompleteElementException e) {
}
}
}
XMLMapperBuilder:
private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
/* 解析 标签 */
return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
}
XMLMapperBuilder:
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
// 提取id属性
String id = resultMapNode.getStringAttribute("id",
resultMapNode.getValueBasedIdentifier());
// 按优先级提取type属性
String type = resultMapNode.getStringAttribute("type",
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType",
resultMapNode.getStringAttribute("javaType"))));
// 提取extends配置
String extend = resultMapNode.getStringAttribute("extends");
// 提取autoMapping配置
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
Class<?> typeClass = resolveClass(type);
Discriminator discriminator = null;
List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
resultMappings.addAll(additionalResultMappings);
List<XNode> resultChildren = resultMapNode.getChildren();
for (XNode resultChild : resultChildren) {
if ("constructor".equals(resultChild.getName())) {
/* 处理 子标签 */
processConstructorElement(resultChild, typeClass, resultMappings);
} else if ("discriminator".equals(resultChild.getName())) {
/* 处理 子标签 */
discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {
List<ResultFlag> flags = new ArrayList<ResultFlag>();
if ("id".equals(resultChild.getName())) {
// 如果是 子标签,添加标记
flags.add(ResultFlag.ID);
}
/* 构建ResultMapping */
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
/* 解析返回ResultMap */
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
// 添加到未完成解析的ResultMap集合中,后续继续解析
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
}
XMLMapperBuilder:
private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
List<XNode> argChildren = resultChild.getChildren();
for (XNode argChild : argChildren) {
List<ResultFlag> flags = new ArrayList<ResultFlag>();
flags.add(ResultFlag.CONSTRUCTOR);
if ("idArg".equals(argChild.getName())) {
// 如果子标签是 添加标记
flags.add(ResultFlag.ID);
}
/* 构建并添加ResultMapping */
resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
}
}
XMLMapperBuilder:
private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
String property; // 提取属性, 提取name,其他标签提取property
if (flags.contains(ResultFlag.CONSTRUCTOR)) {
property = context.getStringAttribute("name");
} else {
property = context.getStringAttribute("property");
}
// 下面是各种标签属性的提取
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String nestedSelect = context.getStringAttribute("select");
/* 递归处理嵌套的resultMapping */
String nestedResultMap = context.getStringAttribute("resultMap",
processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
String notNullColumn = context.getStringAttribute("notNullColumn");
String columnPrefix = context.getStringAttribute("columnPrefix");
String typeHandler = context.getStringAttribute("typeHandler");
String resultSet = context.getStringAttribute("resultSet");
String foreignColumn = context.getStringAttribute("foreignColumn");
boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
// 获取javaType配置的类名或类别名对应的Class对象
Class<?> javaTypeClass = resolveClass(javaType);
@SuppressWarnings("unchecked")
// 获取typeHandler配置的类名或类别名对应的Class对象
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
// 根据jdbcType配置的名称在枚举找到对应的枚举值
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
/* 构建ResultMapping */
return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
}
XMLMapperBuilder:
private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings) throws Exception {
if ("association".equals(context.getName())
|| "collection".equals(context.getName())
|| "case".equals(context.getName())) {
if (context.getStringAttribute("select") == null) {
// 如果是 、 、 三个标签中的一个并且没有配置select属性,则递归解析成ResultMap对象
ResultMap resultMap = resultMapElement(context, resultMappings);
return resultMap.getId();
}
}
return null;
}
MapperBuilderAssistant:
public ResultMapping buildResultMapping(
Class<?> resultType,
String property,
String column,
Class<?> javaType,
JdbcType jdbcType,
String nestedSelect,
String nestedResultMap,
String notNullColumn,
String columnPrefix,
Class<? extends TypeHandler<?>> typeHandler,
List<ResultFlag> flags,
String resultSet,
String foreignColumn,
boolean lazy) {
// 如果配置了javaType则返回javaType对应的Class对象,如果没有配置,则根据父标签配置的类型的相关property属性的相关setter方法的参数类型当做javaType返回
Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
// 从TypeHandler映射中获取对应的TypeHandler,如果获取不到,则通过javaTypeClass和typeHandlerClass实例化TypeHandler
TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
/* 解析组合的column属性 */
List<ResultMapping> composites = parseCompositeColumnName(column);
// 将解析后的每个属性封装到ResultMapping对象中返回
return new ResultMapping.Builder(configuration, property, column, javaTypeClass)
.jdbcType(jdbcType)
.nestedQueryId(applyCurrentNamespace(nestedSelect, true))
.nestedResultMapId(applyCurrentNamespace(nestedResultMap, true))
.resultSet(resultSet)
.typeHandler(typeHandlerInstance)
.flags(flags == null ? new ArrayList<ResultFlag>() : flags)
.composites(composites)
.notNullColumns(parseMultipleColumnNames(notNullColumn))
.columnPrefix(columnPrefix)
.foreignColumn(foreignColumn)
.lazy(lazy)
.build();
}
MapperBuilderAssistant:
private List<ResultMapping> parseCompositeColumnName(String columnName) {
List<ResultMapping> composites = new ArrayList<ResultMapping>();
// column属性可以这样配置:column="{prop1=col1,prop2=col2}"
if (columnName != null && (columnName.indexOf('=') > -1 || columnName.indexOf(',') > -1)) {
StringTokenizer parser = new StringTokenizer(columnName, "{}=, ", false);
while (parser.hasMoreTokens()) {
String property = parser.nextToken(); // prop1
String column = parser.nextToken(); // col1
// 将解析后的属性封装到ResultMapping对象中
ResultMapping complexResultMapping = new ResultMapping.Builder(
configuration, property, column, configuration.getTypeHandlerRegistry().getUnknownTypeHandler()).build();
composites.add(complexResultMapping);
}
}
return composites;
}
下面我们来看
子标签的解析:
XMLMapperBuilder:
private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
// 各个属性的提取
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String typeHandler = context.getStringAttribute("typeHandler");
// 获取javaType配置的类名或类别名对应的Class对象
Class<?> javaTypeClass = resolveClass(javaType);
// 获取typeHandler配置的类名或类别名对应的Class对象
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
// 根据jdbcType配置的名称在枚举找到对应的枚举值
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
Map<String, String> discriminatorMap = new HashMap<String, String>();
// 子标签
for (XNode caseChild : context.getChildren()) {
// 提取value属性
String value = caseChild.getStringAttribute("value");
// 提取resultMap属性,递归处理嵌套的resultMapping,上面已经分析过
String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings));
discriminatorMap.put(value, resultMap);
}
/* 构建鉴别器 */
return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
}
MapperBuilderAssistant:
public Discriminator buildDiscriminator(
Class<?> resultType,
String column,
Class<?> javaType,
JdbcType jdbcType,
Class<? extends TypeHandler<?>> typeHandler,
Map<String, String> discriminatorMap) {
// 构建ResultMapping
ResultMapping resultMapping = buildResultMapping(
resultType,
null,
column,
javaType,
jdbcType,
null,
null,
null,
null,
typeHandler,
new ArrayList<ResultFlag>(),
null,
null,
false);
Map<String, String> namespaceDiscriminatorMap = new HashMap<String, String>();
for (Map.Entry<String, String> e : discriminatorMap.entrySet()) {
String resultMap = e.getValue();
// 应用当前命名空间,命名空间+resultMap的id
resultMap = applyCurrentNamespace(resultMap, true);
namespaceDiscriminatorMap.put(e.getKey(), resultMap);
}
// 将解析好的属性封装到Discriminator对象中构建鉴别器
return new Discriminator.Builder(configuration, resultMapping, namespaceDiscriminatorMap).build();
}
接下来就是构建并返回ResultMap对象了:
public ResultMap resolve() {
/* 将resultMap添加到configuration对象中并返回 */
return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
}
MapperBuilderAssistant:
public ResultMap addResultMap(
String id,
Class<?> type,
String extend,
Discriminator discriminator,
List<ResultMapping> resultMappings,
Boolean autoMapping) {
// 分别对id和extend应用当前命名空间,命名空间+resultMap的id
id = applyCurrentNamespace(id, false);
extend = applyCurrentNamespace(extend, true);
if (extend != null) {
// 如果configuration对象中不包含extend对应的resultMap,抛出IncompleteElementException,添加到未完成解析的ResultMap集合中,后续继续解析
if (!configuration.hasResultMap(extend)) {
throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
}
// 获取configuration对象中extend对应的resultMap
ResultMap resultMap = configuration.getResultMap(extend);
// 复制一份extend对应的resultMap中的resultMapping
List<ResultMapping> extendedResultMappings = new ArrayList<ResultMapping>(resultMap.getResultMappings());
// 移除掉与当前resultMap中相同的resultMapping
extendedResultMappings.removeAll(resultMappings);
boolean declaresConstructor = false;
for (ResultMapping resultMapping : resultMappings) {
// 如果有CONSTRUCTOR标记也就是包含 标签,做一个标记
if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
declaresConstructor = true;
break;
}
}
// 如果当前resultMap中配置了 标签,则溢出extend对应的resultMap中标记为CONSTRUCTOR的resultMapping
if (declaresConstructor) {
Iterator<ResultMapping> extendedResultMappingsIter = extendedResultMappings.iterator();
while (extendedResultMappingsIter.hasNext()) {
if (extendedResultMappingsIter.next().getFlags().contains(ResultFlag.CONSTRUCTOR)) {
extendedResultMappingsIter.remove();
}
}
}
// 将extend对应的resultMapping添加到当前resultMapping集合中
resultMappings.addAll(extendedResultMappings);
}
// 将解析好的各个属性封装到ResultMap对象中返回
ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping)
.discriminator(discriminator)
.build();
// 添加到configuration对象的ResultMap映射集合中
configuration.addResultMap(resultMap);
return resultMap;
}
标签的解析到这里就完成了,下面是
标签的解析:
XMLMapperBuilder:
private void sqlElement(List<XNode> list) throws Exception {
if (configuration.getDatabaseId() != null) {
/* 解析sql标签,携带databaseId配置 */
sqlElement(list, configuration.getDatabaseId());
}
/* 解析sql标签,不带databaseId配置 */
sqlElement(list, null);
}
XMLMapperBuilder:
private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
for (XNode context : list) {
// 提取databaseId配置
String databaseId = context.getStringAttribute("databaseId");
// 提取id配置
String id = context.getStringAttribute("id");
// 应用当前命名空间,命名空间+配置的id
id = builderAssistant.applyCurrentNamespace(id, false);
/* 判断databaseId配置是否匹配 */
if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
// 添加映射关系
sqlFragments.put(id, context);
}
}
}
XMLMapperBuilder:
private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
// 如果配置了全局的databaseId,当判断当前 标签配置的databaseId与全局的databaseId是否相同
if (requiredDatabaseId != null) {
if (!requiredDatabaseId.equals(databaseId)) {
return false;
}
} else {
// 如果没有配置全局的databaseId,则当前 标签也不能配置databaseId
if (databaseId != null) {
return false;
}
// 如果id已经在映射关系中存在,则判断是否配置了databaseId
if (this.sqlFragments.containsKey(id)) {
XNode context = this.sqlFragments.get(id);
if (context.getStringAttribute("databaseId") != null) {
return false;
}
}
}
return true;
}
这里的
标签解析只是添加了映射,真正的应用才后面。下面是、
、
、
四个标签的解析:
XMLMapperBuilder:
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
/* 解析,携带databaseId配置 */
buildStatementFromContext(list, configuration.getDatabaseId());
}
/* 解析,不带databaseId配置 */
buildStatementFromContext(list, null);
}
XMLMapperBuilder:
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
/* 解析 */
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
// 添加到未完成解析statement元素集合中,后续继续解析
configuration.addIncompleteStatement(statementParser);
}
}
}
XMLStatementBuilder:
public void parseStatementNode() {
// 提取id配置
String id = context.getStringAttribute("id");
// 提取databaseId配置
String databaseId = context.getStringAttribute("databaseId");
// 判断是否匹配,上面分析过
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
// 各个属性的提取
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String parameterType = context.getStringAttribute("parameterType");
// 获取parameterType配置的类名或类别名对应的Class对象
Class<?> parameterTypeClass = resolveClass(parameterType);
String resultMap = context.getStringAttribute("resultMap");
String resultType = context.getStringAttribute("resultType");
String lang = context.getStringAttribute("lang");
// 获取lang配置对应的语言驱动,在构造Configuration对象时,Mybatis注册了XMLLanguageDriver、RawLanguageDriver两个语言驱动,并将XMLLanguageDriver设置为默认的语言驱动
LanguageDriver langDriver = getLanguageDriver(lang);
// 获取resultType配置的类名或类别名对应的Class对象
Class<?> resultTypeClass = resolveClass(resultType);
String resultSetType = context.getStringAttribute("resultSetType");
// 根据statementType配置的名称在枚举找到对应的枚举值,默认为PREPARED
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
// 根据resultSetType配置的名称在枚举找到对应的枚举值
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
String nodeName = context.getNode().getNodeName();
// 根据标签的名称在SqlCommandType枚举中找到对应的枚举值,如对应SELECT枚举值
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
// 提取flushCache配置,标签默认为false,其他为true
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
// 提取useCache配置,标签默认为true,其他为false
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
/* 应用 包含的 片段 */
includeParser.applyIncludes(context.getNode());
/* 解析 标签 */
processSelectKeyNodes(id, parameterTypeClass, langDriver);
/* 创建SqlSource */
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
String resultSets = context.getStringAttribute("resultSets");
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
// 应用当前命名空间,命名空间+keyStatementId
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
// 不同情况的KeyGenerator选择
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
/* 构建MappedStatement并添加到configuration对象中 */
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
XMLIncludeTransformer:
public void applyIncludes(Node source) {
Properties variablesContext = new Properties();
Properties configurationVariables = configuration.getVariables();
if (configurationVariables != null) {
// 复制一份configuration对象中的全局变量
variablesContext.putAll(configurationVariables);
}
/* 应用包含的sql片段 */
applyIncludes(source, variablesContext, false);
}
XMLIncludeTransformer:
private void applyIncludes(Node source, final Properties variablesContext, boolean included) {
// 如果是 标签
if (source.getNodeName().equals("include")) {
/* 提取refid对应的sql片段的Node */
Node toInclude = findSqlFragment(getStringAttribute(source, "refid"), variablesContext);
/* 从节点定义中读取占位符和它们的值 */
Properties toIncludeContext = getVariablesContext(source, variablesContext);
// 将包含的sql片段节点作为参数递归此方法
applyIncludes(toInclude, toIncludeContext, true);
if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
// 如果当前节点和被包含节点不在同一个文档中,则将被包含节点导入当前节点所在的文档中
toInclude = source.getOwnerDocument().importNode(toInclude, true);
}
// 将当前节点替换成被包含节点
source.getParentNode().replaceChild(toInclude, source);
while (toInclude.hasChildNodes()) {
// 将子节点放在被包含节点的前面
toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);
}
// 从父节点中移除被包含节点
toInclude.getParentNode().removeChild(toInclude);
} else if (source.getNodeType() == Node.ELEMENT_NODE) {
NodeList children = source.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
// 如果是元素类型的Node如,就遍历子节点递归此方法
applyIncludes(children.item(i), variablesContext, included);
}
} else if (included && source.getNodeType() == Node.TEXT_NODE
&& !variablesContext.isEmpty()) {
// 如果是文本类型的Node,则解析并设置节点值,主要是替换节点值中声明的变量如${var1}
source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
}
}
XMLIncludeTransformer:
private Node findSqlFragment(String refid, Properties variables) {
// 解析refid中声明的变量,如${var1}
refid = PropertyParser.parse(refid, variables);
// 应用当前命名空间,命名空间+refid
refid = builderAssistant.applyCurrentNamespace(refid, true);
try {
// 根据refid从之前解析 标签时添加的映射中获取对应的节点
XNode nodeToInclude = configuration.getSqlFragments().get(refid);
// 复制一份返回
return nodeToInclude.getNode().cloneNode(true);
} catch (IllegalArgumentException e) {
throw new IncompleteElementException("Could not find SQL statement to include with refid '" + refid + "'", e);
}
}
XMLIncludeTransformer:
private Properties getVariablesContext(Node node, Properties inheritedVariablesContext) {
Map<String, String> declaredProperties = null;
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i); // 子节点也就是 标签
if (n.getNodeType() == Node.ELEMENT_NODE) {
// 提取name属性
String name = getStringAttribute(n, "name");
// 提取value属性,并解析属性值中声明的变量
String value = PropertyParser.parse(getStringAttribute(n, "value"), inheritedVariablesContext);
if (declaredProperties == null) {
declaredProperties = new HashMap<String, String>();
}
// 添加到声明的属性映射中
if (declaredProperties.put(name, value) != null) {
// 重复声明抛异常
throw new BuilderException("Variable " + name + " defined twice in the same include definition");
}
}
}
if (declaredProperties == null) {
// 声明属性为空直接返回继承的全局变量
return inheritedVariablesContext;
} else {
// 声明属性不为空则将两者放入新的Properties对象中返回
Properties newProperties = new Properties();
newProperties.putAll(inheritedVariablesContext);
newProperties.putAll(declaredProperties);
return newProperties;
}
}
下面是
标签的解析
XMLStatementBuilder:
private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
List<XNode> selectKeyNodes = context.evalNodes("selectKey");
if (configuration.getDatabaseId() != null) {
/* 解析selectKey节点,携带databaseId配置 */
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
}
/* 解析selectKey节点,不带databaseId配置 */
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
// 解析完成之后从父节点中移除掉
removeSelectKeyNodes(selectKeyNodes);
}
XMLStatementBuilder:
private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
for (XNode nodeToHandle : list) {
// 设置id为父节点的id属性加上!selectKey后缀
String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
String databaseId = nodeToHandle.getStringAttribute("databaseId");
// 判断databaseId配置是否匹配,上文分析过
if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
/* 解析selectKey节点 */
parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
}
}
}
XMLStatementBuilder:
private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
// 各个属性的提取
String resultType = nodeToHandle.getStringAttribute("resultType");
// 解析resultType对应的类名或类别名
Class<?> resultTypeClass = resolveClass(resultType);
StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
// 一些默认值的声明
boolean useCache = false;
boolean resultOrdered = false;
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
Integer fetchSize = null;
Integer timeout = null;
boolean flushCache = false;
String parameterMap = null;
String resultMap = null;
ResultSetType resultSetTypeEnum = null;
/* 创建SqlSource */
SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
SqlCommandType sqlCommandType = SqlCommandType.SELECT;
/* 添加MappedStatement */
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);
// 应用当前命名空间,命名空间+id
id = builderAssistant.applyCurrentNamespace(id, false);
MappedStatement keyStatement = configuration.getMappedStatement(id, false);
// 添加SelectKeyGenerator,在sql执行前后为参数赋相应的值
configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
}
XMLLanguageDriver:
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
/* 解析节点,创建SqlSource */
return builder.parseScriptNode();
}
XMLScriptBuilder:
public SqlSource parseScriptNode() {
/* 解析动态标签 */
List<SqlNode> contents = parseDynamicTags(context);
MixedSqlNode rootSqlNode = new MixedSqlNode(contents);
SqlSource sqlSource = null;
// 根据解析时判断的是否是动态标签的结果来创建不同的SqlSource
if (isDynamic) {
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
return sqlSource;
}
XMLScriptBuilder:
List<SqlNode> parseDynamicTags(XNode node) {
List<SqlNode> contents = new ArrayList<SqlNode>();
NodeList children = node.getNode().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
XNode child = node.newXNode(children.item(i));
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
String data = child.getStringBody("");
TextSqlNode textSqlNode = new TextSqlNode(data);
/* 判断文本类型的node是否是动态的 */
if (textSqlNode.isDynamic()) {
contents.add(textSqlNode);
isDynamic = true;
} else {
contents.add(new StaticTextSqlNode(data));
}
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) {
String nodeName = child.getNode().getNodeName();
/* 获取动态节点的处理器 */
NodeHandler handler = nodeHandlers(nodeName);
if (handler == null) {
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
}
/* 处理动态节点 */
handler.handleNode(child, contents);
isDynamic = true;
}
}
return contents;
}
TextSqlNode:
public boolean isDynamic() {
DynamicCheckerTokenParser checker = new DynamicCheckerTokenParser();
/* 创建解析器 */
GenericTokenParser parser = createParser(checker);
/* 解析 */
parser.parse(text);
return checker.isDynamic();
}
TextSqlNode:
private GenericTokenParser createParser(TokenHandler handler) {
return new GenericTokenParser("${", "}", handler);
}
GenericTokenParser:
public String parse(String text) {
if (text == null || text.isEmpty()) {
return ""; // 文本为空返回空字符串
}
char[] src = text.toCharArray();
int offset = 0;
// openToken:${,closeToken:}
int start = text.indexOf(openToken, offset);
if (start == -1) {
return text; // openToken在文本中不存在,返回文本
}
final StringBuilder builder = new StringBuilder();
StringBuilder expression = null;
while (start > -1) {
// 如果openToken前面是反斜杠\转义字符,移除掉并继续
if (start > 0 && src[start - 1] == '\\') {
builder.append(src, offset, start - offset - 1).append(openToken);
offset = start + openToken.length();
} else {
// 找到了openToken,下面要找closeToken
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] == '\\') {
// 同样的,如果closeToken前面是反斜杠\转义字符,移除掉并继续
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);
offset = end + closeToken.length();
break;
}
}
if (end == -1) {
// closeToken没有找到的情况
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);
}
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
return builder.toString();
}
TextSqlNode.DynamicCheckerTokenParser:
public String handleToken(String content) {
this.isDynamic = true; // 将动态标记设置为true
return null;
}
XMLScriptBuilder:
NodeHandler nodeHandlers(String nodeName) {
Map<String, NodeHandler> map = new HashMap<String, NodeHandler>();
map.put("trim", new TrimHandler());
map.put("where", new WhereHandler());
map.put("set", new SetHandler());
map.put("foreach", new ForEachHandler());
map.put("if", new IfHandler());
map.put("choose", new ChooseHandler());
map.put("when", new IfHandler());
map.put("otherwise", new OtherwiseHandler());
map.put("bind", new BindHandler());
return map.get(nodeName);
}
这里我们看到了Mybatis提供的一些动态标签的处理器,如
、
、
等,我们以
标签为例来看它如何处理动态标签,而处理过后节点的应用则是在mapper方法执行的过程中,我们会在后续的文章中进行详细讲解,其他动态标签的处理也是类似的:
XMLScriptBuilder.IfHandler:
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
// 递归解析当前节点的动态子节点
List<SqlNode> contents = parseDynamicTags(nodeToHandle);
MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
// 提取 标签test属性配置
String test = nodeToHandle.getStringAttribute("test");
// 构建相关Node节点
IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
targetContents.add(ifSqlNode);
}
解析
标签最后是构建并添加MappedStatement:
MapperBuilderAssistant:
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
// 应用当前命名空间,命名空间+id
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
// 将各个解析好的属性复制给MappedStatement.Builder对象中的MappedStatement实例的各个属性
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
/* 获取参数映射 */
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
// 返回MappedStatement对象
MappedStatement statement = statementBuilder.build();
// 添加到configuration对象中
configuration.addMappedStatement(statement);
return statement;
}
MapperBuilderAssistant:
private ParameterMap getStatementParameterMap(
String parameterMapName,
Class<?> parameterTypeClass,
String statementId) {
parameterMapName = applyCurrentNamespace(parameterMapName, true);
ParameterMap parameterMap = null;
// parameterMap已经不推荐使用
if (parameterMapName != null) {
try {
parameterMap = configuration.getParameterMap(parameterMapName);
} catch (IllegalArgumentException e) {
throw new IncompleteElementException("Could not find parameter map " + parameterMapName, e);
}
} else if (parameterTypeClass != null) {
List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
// paramType方式的配置,构建ParameterMap对象
parameterMap = new ParameterMap.Builder(
configuration,
statementId + "-Inline",
parameterTypeClass,
parameterMappings).build();
}
return parameterMap;
}
标签解析完成了,下面会继续、
、
、
四个标签的解析,后面的流程在解析
标签时已经分析过,同样都会创建SqlSource、解析动态标签、构建MappedStatement等,这里不再赘述。最后就是将解析好的Configuration对象封装到DefaultSqlSessionFactory中返回。
SqlSessionFactoryBuilder:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
到这里,整个Mybatis标签解析的源码就分析完了。