和spring框架的IoC容器初始化一样,mybatis也会通过定位、解析相应的配置文件完成自己的初始化。mybatis的配置文件主要有mybatis-config.xml核心配置文件及一系列映射配置文件,另外,mybatis也会根据注解进行配置。 ## 1 BaseBuilder mybatis初始化的主要内容是加载并解析mybatis-config.xml配置文件、映射配置文件以及相关的注解信息。mybatis的初始化入口是SqlSessionFactoryBuilder的build()方法。 ```java public class SqlSessionFactoryBuilder { public SqlSessionFactory build(Reader reader) { return build(reader, null, null); } public SqlSessionFactory build(Reader reader, String environment) { return build(reader, environment, null); } public SqlSessionFactory build(Reader reader, Properties properties) { return build(reader, null, properties); } /** * build方法的主要实现 */ public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { // SqlSessionFactory会创建XMLConfigBuilder对象来解析mybatis-config.xml配置文件 // XMLConfigBuilder继承自BaseBuilder抽象类,顾名思义这一系的类使用了 建造者设计模式 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); // 解析配置文件的内容 到Configuration对象,根据到Configuration对象 // 创建DefaultSqlSessionFactory对象,然后返回 return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { // 关闭配置文件输入流 reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } ``` BaseBuilder中的核心字段如下: ```java public abstract class BaseBuilder { // 保存了mybatis的几乎所以核心配置信息,全局唯一 protected final Configuration configuration; // 在mybatis-config.xml中可以通过标签定义别名 protected final TypeAliasRegistry typeAliasRegistry; // 在mybatis-config.xml中可以通过标签添加自定义TypeHandler // TypeHandler用于完成JDBC数据类型与Java类型的相互转换,所有的TypeHandler // 都保存在typeHandlerRegistry中 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,通过BaseBuilder的构造方法可以看到详细内容。 ## 2 XMLConfigBuilder XMLConfigBuilder是BaseBuilder的众多子类之一,主要负责解析mybatis-config.xml配置文件。它通过调用parseConfiguration()方法实现整个解析过程,其中,mybatis-config.xml配置文件中的每个节点都被封装成了一个个相应的解析方法,parseConfiguration()方法只是依次调用了这些解析方法而已。 ```java public class XMLConfigBuilder extends BaseBuilder { // 标记是否解析过mybatis-config.xml文件 private boolean parsed; // 用于解析mybatis-config.xml的解析器 private final XPathParser parser; // 标识配置的名称,默认读取标签的default属性 private String environment; // 创建并缓存Reflector对象 private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory(); /** * 解析的入口,调用了parseConfiguration()进行后续的解析 */ public Configuration parse() { // parsed标志位的处理 if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // 在mybatis-config.xml配置文件中查找节点,并开始解析 parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { try { // 根据root.evalNode("properties")中的值就可以知道具体是解析哪个标签的方法咯 propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(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); } } ``` mybatis中的标签很多,所以相对应的解析方法也很多,这里挑几个比较重要的标签进行分析。 ### 2.1 解析<typeHandlers>标签 ```java 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(packageName)方法 // 扫描指定包中的所有TypeHandler类,并进行注册 typeHandlerRegistry.register(typeHandlerPackage); } else { // Java数据类型 String javaTypeName = child.getStringAttribute("javaType"); // JDBC数据类型 String jdbcTypeName = child.getStringAttribute("jdbcType"); String handlerTypeName = child.getStringAttribute("handler"); Class javaTypeClass = resolveClass(javaTypeName); JdbcType jdbcType = resolveJdbcType(jdbcTypeName); Class typeHandlerClass = resolveClass(handlerTypeName); // 注册 if (javaTypeClass != null) { if (jdbcType == null) { typeHandlerRegistry.register(javaTypeClass, typeHandlerClass); } else { typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass); } } else { typeHandlerRegistry.register(typeHandlerClass); } } } } } ``` ### 2.2 解析<environments>标签 ```java /** * mybatis可以配置多个环境,分别用于开发、测试及生产等, * 但每个SqlSessionFactory实例只能选择其一 */ private void environmentsElement(XNode context) throws Exception { if (context != null) { // 如果未指定XMLConfigBuilder的environment字段,则使用default属性指定的环境 if (environment == null) { environment = context.getStringAttribute("default"); } // 遍历节点 for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { // 实例化TransactionFactory TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); // 创建DataSourceFactory和DataSource DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); DataSource dataSource = dsFactory.getDataSource(); // 创建的Environment对象中封装了上面的TransactionFactory对象和DataSource对象 Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); // 为configuration注入environment属性值 configuration.setEnvironment(environmentBuilder.build()); } } } } ``` ### 2.3 解析<databaseIdProvider>标签 ```java ``` ### 2.4 解析<mappers>标签 ```java ```