mybatis 配置文件mybatis.xml的加载过程
mybatis配置文件的整体加载过程
mybatis几乎所有的用户相关的操作都是再SqlSession上进行的,儿sqlSession是由SqlSessionFactory调用openSession方法创建的.正常情况下,系统中只会出现一个SqlSessionFactory.
SqlSessionFactory是SqlSessionFactoryBuild调用build方法并且传入配置文件创建的.build方法接收一个xml格式的配置文件,
配置文件
下面是一个完整的mybatis的配置文件,里面包含了properties,settings,typeAliaes,typeHandlers,plugins,environments,mappers属性,并且这些属性的出现顺序是固定的,可以没有,但是顺序不能错.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--configuration核心配置文件--> <configuration> <!-- mybatis引入properties的两种方式,1.直接从文件中引入,2.在properties中配置 --> <!-- mybatis中设置的property可以在本配置文件中通过表达式引用.eg:${propertyName}--> <!--引入外部配置文件--> <properties resource="db.properties"> <!-- 直接在properties中定义属性 --> <property name="propertyName" value="propertyValue"/> </properties> <!-- setting mybatis的全局设置,可以改变mybatis的运行时的行为 --> <settings> <!-- 全局性的开启或者关闭所有的映射器配置文件中已经配置的任何缓存,默认为true --> <setting name="cacheEnabled" value="true"/> <!-- 是否延迟加载的全局开关,如果需要特定对象之间不进行延迟加载则可以使用fetchType属性进行覆盖,默认只为false --> <setting name="lazyLoadingEnabled" value="false"/> <!-- 开启时,所有的对象都会直接加载该对象的延迟加载属性,默认为true --> <setting name="aggressiveLazyLoading" value="true"/> <!-- 是否允许单个语句返回多结果集,默认为true,但是需要数据库驱动的支持 --> <setting name="multipleResultSetsEnabled" value="true"/> <!-- 允许jdbc自动生成主键,即当插入数据库的对象没有设置主键,而是依靠数据库自增主键是,该主键会回写到插入数据库的对象中, 但是该属性必须配合xml中insert属性的keyColumn和keyProperty属性使用, 或者配置@Insert注解的@Options注解的keyColumn和keyProperty属性使用 --> <setting name="useGeneratedKeys" value="true"/> <!-- 执行mybatis是否自动人设列到字段或属性 --> <!-- NONE:关闭自动映射 --> <!-- PARTIAL:只会自动映射么有定义嵌套结果映射的字段 --> <!-- FULL:自动映射任何复杂的结果集 --> <setting name="autoMappingBehavior" value="PARTIAL"/> <!-- 指定发现自动映射目标未知列的行为 --> <!-- NONE:没有任何操作 --> <!-- WARING: 发出警告,输出日志org.apache.ibatis.session.AutoMappingUnknownColumnBehavior,但是需要配置日志级别为warn--> <!-- FAILING:映射失败 --> <setting name="autoMappingUnknownColumnBehavior" value="NONE"/> <!-- 配置默认的执行器 --> <!-- SIMPLE:普通执行器,默认的 --> <!-- REUSE:预处理执行器,会使用preparedStatement --> <!-- BATCH:不仅会重用语句还会执行批量更新 --> <setting name="defaultExecutorType" value="SIMPLE"/> <!-- 数据库连接超时时间,单位为秒 ,默认未设置--> <setting name="defaultStatementTimeout" value="1"/> <!-- 设置默认的查询结果集返回条数,在每个查询语句中可以单独设置,默认为未设置 mysql不支持该属性 --> <setting name="defaultFetchSize" value="10"/> <!-- 是否允许在嵌套语句中使用分页。如果允许使用则设置为 false。 默认未false--> <setting name="safeRowBoundsEnabled" value="false"/> <!-- 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 ,默认为true--> <setting name="safeResultHandlerEnabled" value=""/> <!-- 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 默认为false--> <setting name="mapUnderscoreToCamelCase" value="false"/> <!-- MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 --> <setting name="localCacheScope" value="SESSION"/> <!-- 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型.可以为 NULL、VARCHAR 或 OTHER 默认为OTHER--> <setting name="jdbcTypeForNull" value="OTHER"/> <!-- 指定对象的哪些方法触发一次延迟加载。equals,clone,hashCode,toString 等,默认为全部方法 --> <setting name="lazyLoadTriggerMethods" value=""/> <!-- 指定 Enum 使用的默认 TypeHandler.值必须为一个类的全限定名,默认为:org.apache.ibatis.type.EnumTypeHandler --> <setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/> <!-- 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法, 这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的 --> <setting name="callSettersOnNulls" value="false"/> <!-- 当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联).默认值:false --> <setting name="returnInstanceForEmptyRow" value="false"/> <!-- 指定 MyBatis 增加到日志名称的前缀。 默认未设置--> <setting name="logPrefix" value=""/> <!-- 指定 MyBatis 所用日志的具体实现,未指定时将自动查找 . SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING --> <setting name="logImpl" value="SLF4J"/> <!-- 允许使用方法签名中的名称作为语句参数名称.为了使用该特性,你的项目必须采用Java8编译,并且加上 -parameters 选项.默认:true --> <setting name="useActualParamName" value="true"/> <!-- 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。默认未空 --> <!--<setting name="configurationFactory" value=""/>--> </settings> <!-- 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写 --> <typeAliases> <!-- 可以直接指定一个类 --> <!--<typeAlias type="com.monkey.learn.mybatis.entity.Student" alias="student"/>--> <!-- 可以指定一个包 每一个在包中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 com.monkey.learn.mybatis.entity.Studentr 的别名为 student; 若有@Alias("name")注解,则别名为其注解值。见 --> <package name="com.monkey.learn.mybatis.xml.entity"/> <!-- mybatis的内建别名如下: _byte:byte,_long:long,_short:short,_int:int,_integer:int,_double:double,_float:float,_boolean:boolean, string:String,byte:Byte,long:Long,short:Short,int:Integer,integer:Integer,double:Double,float:Float, boolean:Boolean,date:Date,decimal:BigDecimal,bigdecimal:BigDecimal,object:Object,map:Map,hashmap:HashMap, list:List,arraylist:ArrayList,collection:Collection,iterator:Iterator --> </typeAliases> <!-- MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时,都会用typeHandler将获取到的值以合适的方式转换成 Java 类型. typeHandler可以通过继承BaseTypeHandler或者实现TypeHandler来定义. --> <typeHandlers> <!-- 通过类直接指定typeHandler --> <!-- <typeHandler handler="com.monkey.learn.mybatis.handler.StudentJsonTypeHandler" javaType="com.monkey.learn.mybatis.entity.Student" jdbcType="varchar"/>--> <!-- 通过包来指定typeHandler --> <package name="com.monkey.learn.xml.handler"/> </typeHandlers> <!-- 每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法 --> <!-- <objectFactory type="com.monkey.learn.mybatis.factory.StudentFactory"> <property name="propertyName" value="propertyValue"/> </objectFactory>--> <plugins> <plugin interceptor="com.monkey.learn.mybatis.xml.plugin.PagePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins> <!--MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。 例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。 不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driverClassName}"/> <property name="url" value="${druid.url}"/> <property name="username" value="${druid.username}"/> <property name="password" value="${druid.password}"/> </dataSource> </environment> </environments> <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!--> <mappers> <!-- 定义单个mapper --> <mapper resource="mapper/StudentMapper.xml"/> <!-- 扫描整个包 --> <!--<package name="com.monkey.learn.xml.mapper"/>--> </mappers> </configuration>
加载时机
再调用了SqlSessionFactoryBuild的build方法之后,build方法会根据传入的xml配置文件,创建一个XmlConfigBuilder,并且调用parse方法来解析整个xml文件.
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
加载顺序
在XmlConfigBuilder调用parse方法之后,parse方法中会再调用parseConfiguration方法真正的解析xml配置文件.解析的顺序和再xml中出现的顺序是一致的.
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(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);
}
}