目录 配置文件解析入口 解析 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 logImpl; protected Class 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