Mybaits 源码解析 (二)----- 根据配置文件创建SqlSessionFactory(Configuration的创建过程)
目录
配置文件解析入口
解析 properties 配置
解析 settings 配置
settings 节点的解析过程
设置 settings 配置到 Configuration 中
解析 typeAliases 配置
从 typeAlias 节点中解析并注册别名
从指定的包中解析并注册别名
解析 plugins 配置
解析 environments 配置
解析 mappers 配置
创建DefaultSqlSessionFactory
正文
我们使用mybatis操作数据库都是通过SqlSession的API调用,而创建SqlSession是通过SqlSessionFactory。下面我们就看看SqlSessionFactory的创建过程。
回到顶部
配置文件解析入口
我们看看第一篇文章中的测试方法
复制代码
1 public static void main(String[] args) throws IOException {
2 String resource = "mybatis-config.xml";
3 InputStream inputStream = Resources.getResourceAsStream(resource);
4 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
5 SqlSession sqlSession = sqlSessionFactory.openSession();
6 try {
7 Employee employeeMapper = sqlSession.getMapper(Employee.class);
8 List all = employeeMapper.getAll();
9 for (Employee item : all)
10 System.out.println(item);
11 } finally {
12 sqlSession.close();
13 }
14 }
复制代码
首先,我们使用 MyBatis 提供的工具类 Resources 加载配置文件,得到一个输入流。然后再通过 SqlSessionFactoryBuilder 对象的build方法构建 SqlSessionFactory 对象。所以这里的 build 方法是我们分析配置文件解析过程的入口方法。我们看看build里面是代码:
复制代码
public SqlSessionFactory build(InputStream inputStream) {
// 调用重载方法
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 创建配置文件解析器
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 调用 parser.parse() 方法解析配置文件,生成 Configuration 对象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
// 创建 DefaultSqlSessionFactory,将解析配置文件后生成的Configuration传入
return new DefaultSqlSessionFactory(config);
}
复制代码
SqlSessionFactory是通过SqlSessionFactoryBuilder的build方法创建的,build方法内部是通过一个XMLConfigBuilder对象解析mybatis-config.xml文件生成一个Configuration对象。XMLConfigBuilder从名字可以看出是解析Mybatis配置文件的,其实它是继承了一个父类BaseBuilder,其每一个子类多是以XMLXXXXXBuilder命名的,也就是其子类都对应解析一种xml文件或xml文件中一种元素。
我们看看XMLConfigBuilder的构造方法:
复制代码
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
复制代码
可以看到调用了父类的构造方法,并传入一个new Configuration()对象,这个对象也就是最终的Mybatis配置对象
我们先来看看其基类BaseBuilder
复制代码
public abstract class BaseBuilder {
protected final Configuration configuration;
protected final TypeAliasRegistry typeAliasRegistry;
protected final TypeHandlerRegistry typeHandlerRegistry;
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
....
}
复制代码
BaseBuilder中只有三个成员变量,而typeAliasRegistry和typeHandlerRegistry都是直接从Configuration的成员变量获得的,接着我们看看Configuration这个类
Configuration类位于mybatis包的org.apache.ibatis.session目录下,其属性就是对应于mybatis的全局配置文件mybatis-config.xml的配置,将XML配置中的内容解析赋值到Configuration对象中。
由于XML配置项有很多,所以Configuration类的属性也很多。先来看下Configuration对于的XML配置文件示例:
复制代码
复制代码
而对于XML的配置,Configuration类的属性是和XML配置对应的。Configuration类属性如下:
复制代码
public class Configuration {
protected Environment environment;//运行环境
protected boolean safeRowBoundsEnabled = false;
protected boolean safeResultHandlerEnabled = true;
protected boolean mapUnderscoreToCamelCase = false;
protected boolean aggressiveLazyLoading = true; //true:有延迟加载属性的对象被调用时完全加载任意属性;false:每个属性按需要加载
protected boolean multipleResultSetsEnabled = true;//是否允许多种结果集从一个单独的语句中返回
protected boolean useGeneratedKeys = false;//是否支持自动生成主键
protected boolean useColumnLabel = true;//是否使用列标签
protected boolean cacheEnabled = true;//是否使用缓存标识
protected boolean callSettersOnNulls = false;//
protected boolean useActualParamName = true;
protected String logPrefix;
protected Class extends Log> logImpl;
protected Class extends VFS> vfsImpl;
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
protected Set lazyLoadTriggerMethods = new HashSet(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
protected Integer defaultStatementTimeout;
protected Integer defaultFetchSize;
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;//指定mybatis如果自动映射列到字段和属性,PARTIAL会自动映射简单的没有嵌套的结果,FULL会自动映射任意复杂的结果
protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
protected Properties variables = new Properties();
protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
protected ObjectFactory objectFactory = new DefaultObjectFactory();
protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
protected boolean lazyLoadingEnabled = false;//是否延时加载,false则表示所有关联对象即使加载,true表示延时加载
protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
protected String databaseId;
protected Class> configurationFactory;
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
protected final InterceptorChain interceptorChain = new InterceptorChain();
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
protected final Map mappedStatements = new StrictMap("Mapped Statements collection");
protected final Map caches = new StrictMap("Caches collection");
protected final Map resultMaps = new StrictMap("Result Maps collection");
protected final Map parameterMaps = new StrictMap("Parameter Maps collection");
protected final Map keyGenerators = new StrictMap("Key Generators collection");
protected final Set loadedResources = new HashSet(); //已经加载过的resource(mapper)
protected final Map sqlFragments = new StrictMap("XML fragments parsed from previous mappers");
protected final Collection incompleteStatements = new LinkedList();
protected final Collection incompleteCacheRefs = new LinkedList();
protected final Collection incompleteResultMaps = new LinkedList();
protected final Collection incompleteMethods = new LinkedList();
protected final Map cacheRefMap = new HashMap();
//其他方法略
}
复制代码
加载的过程是SqlSessionFactoryBuilder根据xml配置的文件流,通过XMLConfigBuilder的parse方法进行解析得到一个Configuration对象,我们再看看其构造函数
复制代码
1 public Configuration() {
2 this.safeRowBoundsEnabled = false;
3 this.safeResultHandlerEnabled = true;
4 this.mapUnderscoreToCamelCase = false;
5 this.aggressiveLazyLoading = true;
6 this.multipleResultSetsEnabled = true;
7 this.useGeneratedKeys = false;
8 this.useColumnLabel = true;
9 this.cacheEnabled = true;
10 this.callSettersOnNulls = false;
11 this.localCacheScope = LocalCacheScope.SESSION;
12 this.jdbcTypeForNull = JdbcType.OTHER;
13 this.lazyLoadTriggerMethods = new HashSet(Arrays.asList("equals", "clone", "hashCode", "toString"));
14 this.defaultExecutorType = ExecutorType.SIMPLE;
15 this.autoMappingBehavior = AutoMappingBehavior.PARTIAL;
16 this.autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
17 this.variables = new Properties();
18 this.reflectorFactory = new DefaultReflectorFactory();
19 this.objectFactory = new DefaultObjectFactory();
20 this.objectWrapperFactory = new DefaultObjectWrapperFactory();
21 this.mapperRegistry = new MapperRegistry(this);
22 this.lazyLoadingEnabled = false;
23 this.proxyFactory = new JavassistProxyFactory();
24 this.interceptorChain = new InterceptorChain();
25 this.typeHandlerRegistry = new TypeHandlerRegistry();
26 this.typeAliasRegistry = new TypeAliasRegistry();
27 this.languageRegistry = new LanguageDriverRegistry();
28 this.mappedStatements = new Configuration.StrictMap("Mapped Statements collection");
29 this.caches = new Configuration.StrictMap("Caches collection");
30 this.resultMaps = new Configuration.StrictMap("Result Maps collection");
31 this.parameterMaps = new Configuration.StrictMap("Parameter Maps collection");
32 this.keyGenerators = new Configuration.StrictMap("Key Generators collection");
33 this.loadedResources = new HashSet();
34 this.sqlFragments = new Configuration.StrictMap("XML fragments parsed from previous mappers");
35 this.incompleteStatements = new LinkedList();
36 this.incompleteCacheRefs = new LinkedList();
37 this.incompleteResultMaps = new LinkedList();
38 this.incompleteMethods = new LinkedList();
39 this.cacheRefMap = new HashMap();
40 this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
41 this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
42 this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
43 this.typeAliasRegistry.registerAl