mybatis源码阅读-初始化过程(七)

说明

mybatis初始化过程 就是解析xml到封装成Configuration对象 供后续使用

SqlSessionFactoryBuilder

代码例子

     SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder
                .build(ClassLoader.getSystemResourceAsStream("mybatis.xml"));

 

说明

通过build将流交给XMLConfigBuilder处理  XMLConfigBuilder通过parse解析XML封装到Configuration  然后SqlSessionFactoryBuilder 创建DefaultSqlSessionFactory 并将解析的Configuration 设置到DefaultSqlSessionFactory对象的属性

源码

    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            //将流传入XMLConfigBuilder
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            //parser.parse() 解析xml和mapper文件 封装成Configuration并返回 
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                inputStream.close();
            } catch (IOException var13) {
                ;
            }

        }

        return var5;
    }

    public SqlSessionFactory build(Configuration config) {
        //初始化Configuration
        return new DefaultSqlSessionFactory(config);
    }

XMLConfigBuilder

说明

负责解析指定xml并封装成Configuration 对象

源码

public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            //获得根节点configuration
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

    private void parseConfiguration(XNode root) {
        try {
            //解析settings并封装成Properties
            Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
            //解析properties
            this.propertiesElement(root.evalNode("properties"));
            this.loadCustomVfs(settings);
            //解析typeAliases
            this.typeAliasesElement(root.evalNode("typeAliases"));
            //解析plugins
            this.pluginElement(root.evalNode("plugins"));
            //解析objectFactory
            this.objectFactoryElement(root.evalNode("objectFactory"));
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            this.reflectionFactoryElement(root.evalNode("reflectionFactory"));
            this.settingsElement(settings);
            this.environmentsElement(root.evalNode("environments"));
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }

注意root.evalNode为mybatis封装的解析xml的工具类 root为XNode对象 感兴趣可以查看

mapper解析过程

mapperElement(root.evalNode("mappers"))

    private void mapperElement(XNode parent) throws Exception {
        if (parent != null) {
            Iterator i$ = parent.getChildren().iterator();

            while(true) {
                while(i$.hasNext()) {
                    XNode child = (XNode)i$.next();
                    String resource;
                   //2种配置选择    <mappers><mapper resource="ClassesMapper.xml"></mapper><mapper class=""></mapper><package name="com.liqiang.mapper"/></mappers>
                    if ("package".equals(child.getName())) {
                        resource = child.getStringAttribute("name");
                        this.configuration.addMappers(resource);
                    } else {
                        resource = child.getStringAttribute("resource");
                        String url = child.getStringAttribute("url");
                        String mapperClass = child.getStringAttribute("class");
                        XMLMapperBuilder mapperParser;
                        InputStream inputStream;
                        if (resource != null && url == null && mapperClass == null) {
                            ErrorContext.instance().resource(resource);
                            inputStream = Resources.getResourceAsStream(resource);
                            //得到对应的mapper.xml文件 交给XmlMapperBuilder解析 并将结果封装到configuration
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        } else if (resource == null && url != null && mapperClass == null) {
                            ErrorContext.instance().resource(url);
                            inputStream = Resources.getUrlAsStream(url);
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        } else {
                            if (resource != null || url != null || mapperClass == null) {
                                throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                            }

                            Class<?> mapperInterface = Resources.classForName(mapperClass);
                            this.configuration.addMapper(mapperInterface);
                        }
                    }
                }

                return;
            }
        }
    }

XMLMapperBuilder

解析源码

 private void configurationElement(XNode context) {
        try {
            String namespace = context.getStringAttribute("namespace");
            if (namespace != null && !namespace.equals("")) {
                this.builderAssistant.setCurrentNamespace(namespace);
                this.cacheRefElement(context.evalNode("cache-ref"));
                this.cacheElement(context.evalNode("cache"));
                this.parameterMapElement(context.evalNodes("/mapper/parameterMap"));
                this.resultMapElements(context.evalNodes("/mapper/resultMap"));
                this.sqlElement(context.evalNodes("/mapper/sql"));
                this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
            } else {
                throw new BuilderException("Mapper's namespace cannot be empty");
            }
        } catch (Exception var3) {
            throw new BuilderException("Error parsing Mapper XML. Cause: " + var3, var3);
        }
    }

图解

图片来源:https://my.oschina.net/zudajun/blog/668738

最终这些标签都会以对象的形式封装起来以map格式保存到configuration 的map里面key为id如:

public class Configuration {
    protected final Map<String, MappedStatement> mappedStatements;
    protected final Map<String, Cache> caches;
    protected final Map<String, ResultMap> resultMaps;
    protected final Map<String, ParameterMap> parameterMaps;
    protected final Map<String, KeyGenerator> keyGenerators;
}

其他

typeAlias package扫描

<typeAliases>
    <typeAlias alias="Student" type="com.mybatis3.domain.Student" />
    <typeAlias alias="Teacher" type="com.mybatis3.domain.Teacher" />
    <package name="com.mybatis3.domain" />
</typeAliases>

XMLConfigBuilder

 private void typeAliasesElement(XNode parent) {
        if (parent != null) {
            Iterator i$ = parent.getChildren().iterator();

            while(i$.hasNext()) {
                XNode child = (XNode)i$.next();
                String alias;
                //如果是package反射获得类下面的所有类型 registerAlias
                if ("package".equals(child.getName())) {
                    alias = child.getStringAttribute("name");
                    this.configuration.getTypeAliasRegistry().registerAliases(alias);
                } else {
                    alias = child.getStringAttribute("alias");
                    String type = child.getStringAttribute("type");

                    try {
                        
                        Class<?> clazz = Resources.classForName(type);
                        if (alias == null) {
                            //如果没有指定别名 内部会读取类上面的Alias注解的value为别名
                            this.typeAliasRegistry.registerAlias(clazz);
                        } else {
                            //注册
                            this.typeAliasRegistry.registerAlias(alias, clazz);
                        }
                    } catch (ClassNotFoundException var7) {
                        throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + var7, var7);
                    }
                }
            }
        }

    }

简写和全名称都能执行sql原理

表现形式

Student std  = sqlSession.selectOne("findStudentById", 1);
Student std  = sqlSession.selectOne("com.mybatis3.mappers.StudentMapper.findStudentById", 1);

 

原理

mybatis重写保存Statement的Configuration.StrictMap

this.mappedStatements = new Configuration.StrictMap("Mapped Statements collection");
        this.caches = new Configuration.StrictMap("Caches collection");
        this.resultMaps = new Configuration.StrictMap("Result Maps collection");
        this.parameterMaps = new Configuration.StrictMap("Parameter Maps collection");
        this.keyGenerators = new Configuration.StrictMap("Key Generators collection");】

 

    public V put(String key, V value) {
        if (this.containsKey(key)) {
            throw new IllegalArgumentException(this.name + " already contains value for " + key);
        } else {
            //判断是否是配的全名称
            if (key.contains(".")) {
                //获得简写形式
                String shortKey = this.getShortName(key);
                //判断是否存在
                if (super.get(shortKey) == null) {
                     //如果不存在直接放进去
                    super.put(shortKey, value);
                } else {
                    //如果重复 则保存一个占位符  get的时候判断值是这个占位符 则抛错
                    super.put(shortKey, new Configuration.StrictMap.Ambiguity(shortKey));
                }
            }
            //原始配置保存
            return super.put(key, value);
        }
    }
    public V get(Object key) {
        V value = super.get(key);
        if (value == null) {
            throw new IllegalArgumentException(this.name + " does not contain value for " + key);
            //如果是Ambiguity 则抛错
        } else if (value instanceof Configuration.StrictMap.Ambiguity) {
            throw new IllegalArgumentException(((Configuration.StrictMap.Ambiguity)value).getSubject() + " is ambiguous in " + this.name + " (try using the full name including the namespace, or rename one of the entries)");
        } else {
            return value;
        }
    }
}

 

posted @ 2019-04-12 17:18  意犹未尽  阅读(396)  评论(0编辑  收藏  举报