在mybatis源码中找到XmlConfigBuilderTest,以debug模式运行shouldSuccessfullyLoadXMLConfigFile()。
初始化
首先创建XMLConfigBuilder对象,在构造方法中:
-
创建Configuration对象,该对象存储各种配置信息,构造方法内注册一些别名信息的映射,例如key是JDBC,value是JdbcTransactionFactory.class
-
通过ThreadLocal获取ErrorContext,用于保存上下文信息,方便抛异常的时候获得各种信息
解析配置
接着调用XMLConfigBuilder.parse()解析xml文件:
-
XMLConfigBuilder.parse(),使用全局变量标记避免重复加载配置,返回配置对象(Configuration)
-
XMLConfigBuilder.parse().parseConfiguration(),解析配置文件内<configuration>的各个子节点,要求各个子节点不能重复,若重复会抛出异常:
元素类型为 "configuration" 的内容必须匹配 "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)"
-
解析<settings>节点,转换成Properties对象,它是一个HashTable。接着对Properties对象的key做检查,看看是否是Configuration类的的成员变量。检查的方法是把拥有setter方法的成员变量名,存储到一个集合中,通过contains()判断,如果不包含,则意味着<setting>节点有错误的配置,于是抛出异常
-
解析<typeAliases>节点,配置别名。子节点只能是<package>或者<typeAlias>节点。
-
如果子节点是<typeAlias>,则建立别名到class对象的映射。如果没有指定别名,默认别名class.getSimpleName(),如果配置了Alias注解,则使用注解的值作为别名,别名使用小写。
-
如果子节点是<package>,则以整个包为单位配置别名
-
-
解析<plugins>节点,通过反射创建拦截器对象,将该对象添加到configuration对象的拦截器链(一个ArrayList)中
-
解析<objectWrapperFactory>节点,通过反射,生成对象工厂
-
解析<reflectorFactory>节点,通过反射生成反射器工厂,反射器缓存了类对象的相关信息例如setter方法集合和getter方法集合
-
将<setting>节点解析出来的配置应用到configuration对象中,调用configuration每个成员变量的setter方法,以及properties对象的getorDefault方法获取值
-
解析<environments>节点,解析数据库链接地址、账号密码等配置,解析<transactionManager>和<dataSource>节点,生成数据源和事务工厂对象
-
解析<<databaseIdProvider>>节点
-
解析<typeHandlers>节点,通过别名查找缓存或者class.forName获得TypeHandler的class对象,再反射生成对象,将该对象缓存起来,结构为Map<JavaType,Map<JdbcType,TypeHandler<?>>>, 映射的关系为java类型->Jdbc类型->TypeHandler。同时存到另外一份缓存中,结构为Map<Class<?>,TypeHandler<?>>。
-
如果子节点是<typeHandler>
-
如果子节点是<package>,则以整个包为单位获取TypeHandler
-
-
解析<mappers>节点,从磁盘读取xxxMapper.xml到内存并解析成相关的配置对象,具体实现在XMLMapperBuilder中,在另一篇文章
-
附录
典型的mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!-- ? copyright 2009-2016 the original author or authors. ? Licensed under the Apache License,Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at ? http://www.apache.org/licenses/LICENSE-2.0 ? Unless required by applicable law or agreed to in writing,software distributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,either express or implied. See the License for the specific language governing permissions and limitations under the License. ? --> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> ? <configuration> ? <properties resource="org/apache/ibatis/databases/blog/blog-derby.properties"/> ? <settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="false"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> </settings> ? <typeAliases> <package name="org.apache.ibatis.domain"/> </typeAliases> <!--<typeAliases>--> <!--<typeAlias alias="Author" type="org.apache.ibatis.domain.blog.Author"/>--> <!--<typeAlias alias="Blog" type="org.apache.ibatis.domain.blog.Blog"/>--> <!--<typeAlias alias="Comment" type="org.apache.ibatis.domain.blog.Comment"/>--> <!--<typeAlias alias="Post" type="org.apache.ibatis.domain.blog.Post"/>--> <!--<typeAlias alias="Section" type="org.apache.ibatis.domain.blog.Section"/>--> <!--<typeAlias alias="Tag" type="org.apache.ibatis.domain.blog.Tag"/>--> <!--</typeAliases>--> <typeHandlers> <typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/> </typeHandlers> ? <objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory"> <property name="objectFactoryProperty" value="100"/> </objectFactory> ? <plugins> <plugin interceptor="org.apache.ibatis.builder.ExamplePlugin"> <property name="pluginProperty" value="100"/> </plugin> </plugins> ? <environments default="development"> <environment id="development"> <transactionManager type="JDBC"> <property name="" value=""/> </transactionManager> <dataSource type="UNPOOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> ? <mappers> <mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/> <mapper resource="org/apache/ibatis/builder/BlogMapper.xml"/> <mapper resource="org/apache/ibatis/builder/CachedAuthorMapper.xml"/> <mapper resource="org/apache/ibatis/builder/PostMapper.xml"/> <mapper resource="org/apache/ibatis/builder/nestedBlogMapper.xml"/> </mappers> ? </configuration>
单元测试方法
@Test void shouldSuccessfullyLoadXMLConfigFile() throws Exception { // System.setProperty(XPathParser.KEY_USE_XSD,"true"); String resource = "org/apache/ibatis/builder/xsd/CustomizedSettingsMapperConfig.xml"; try (InputStream inputStream = Resources.getResourceAsstream(resource)) { XMLConfigBuilder builder = new XMLConfigBuilder(inputStream); Configuration config = builder.parse(); ? assertEquals(AutoMappingBehavior.NONE,config.getAutoMappingBehavior()); assertEquals(AutoMappingUnkNownColumnBehavior.WARNING,config.getAutoMappingUnkNownColumnBehavior()); assertFalse(config.isCacheEnabled()); assertTrue(config.getProxyFactory() instanceof cglibProxyFactory); assertTrue(config.isLazyLoadingEnabled()); assertTrue(config.isAggressiveLazyLoading()); assertFalse(config.isMultipleResultSetsEnabled()); assertFalse(config.isUseColumnLabel()); assertTrue(config.isUseGeneratedKeys()); assertEquals(ExecutorType.BATCH,config.getDefaultExecutorType()); assertEquals(Integer.valueOf(10),config.getDefaultStatementTimeout()); assertEquals(Integer.valueOf(100),config.getDefaultFetchSize()); assertTrue(config.isMapUnderscoreToCamelCase()); assertTrue(config.isSafeRowBoundsEnabled()); assertEquals(LocalCacheScope.STATEMENT,config.getLocalCacheScope()); assertEquals(JdbcType.NULL,config.getJdbcTypeForNull()); assertEquals(new HashSet<>(Arrays.asList("equals","clone","hashCode","toString","xxx")),config.getLazyLoadTriggerMethods()); assertFalse(config.isSafeResultHandlerEnabled()); assertTrue(config.getDefaultScriptingLanguageInstance() instanceof RawLanguageDriver); assertTrue(config.isCallSettersOnNulls()); assertEquals("mybatis_",config.getLogPrefix()); assertEquals(Slf4jImpl.class.getName(),config.getLogImpl().getName()); assertEquals(JBoss6VFS.class.getName(),config.getVfsImpl().getName()); assertEquals(String.class.getName(),config.getConfigurationFactory().getName()); ? assertEquals(Author.class,config.getTypeAliasRegistry().getTypeAliases().get("blogauthor")); assertEquals(Blog.class,config.getTypeAliasRegistry().getTypeAliases().get("blog")); assertEquals(Cart.class,config.getTypeAliasRegistry().getTypeAliases().get("cart")); ? assertTrue(config.getTypeHandlerRegistry().getTypeHandler(Integer.class) instanceof CustomIntegerTypeHandler); assertTrue(config.getTypeHandlerRegistry().getTypeHandler(Long.class) instanceof CustomLongTypeHandler); assertTrue(config.getTypeHandlerRegistry().getTypeHandler(String.class) instanceof CustomStringTypeHandler); assertTrue(config.getTypeHandlerRegistry().getTypeHandler(String.class,JdbcType.VARCHAR) instanceof CustomStringTypeHandler); ? ExampleObjectFactory objectFactory = (ExampleObjectFactory)config.getobjectFactory(); assertEquals(1,objectFactory.getProperties().size()); assertEquals("100",objectFactory.getProperties().getProperty("objectFactoryProperty")); ? assertTrue(config.getobjectWrapperFactory() instanceof CustomObjectWrapperFactory); ? assertTrue(config.getReflectorFactory() instanceof CustomreflectorFactory); ? ExamplePlugin plugin = (ExamplePlugin)config.getInterceptors().get(0); assertEquals(1,plugin.getProperties().size()); assertEquals("100",plugin.getProperties().getProperty("pluginProperty")); ? Environment environment = config.getEnvironment(); assertEquals("development",environment.getId()); assertTrue(environment.getDataSource() instanceof UnpooledDataSource); assertTrue(environment.getTransactionFactory() instanceof JdbcTransactionFactory); ? assertEquals("derby",config.getDatabaseId()); ? assertEquals(4,config.getMapperRegistry().getMappers().size()); assertTrue(config.getMapperRegistry().hasMapper(CachedAuthorMapper.class)); assertTrue(config.getMapperRegistry().hasMapper(CustomMapper.class)); assertTrue(config.getMapperRegistry().hasMapper(BlogMapper.class)); assertTrue(config.getMapperRegistry().hasMapper(nestedBlogMapper.class)); } finally { // System.clearProperty(XPathParser.KEY_USE_XSD); } }
一系列默认别名
基本类型
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); }
其他类型
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); }