zoukankan      html  css  js  c++  java
  • 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;
            }
        }
    }
  • 相关阅读:
    <img/>标签onerror事件在IE下的bug和解决方法
    IIS启用Gzip压缩造成OpenFlashChart不能正常显示问题及解决方法
    小心枚举陷阱
    "动软.Net代码生成器"的一次扩展经历
    旁听面试杂想
    .NET Remoting学习点滴(二):基本概念
    十字路口
    表变量和临时表
    动态创建WebService
    拼接SQL造成的意想不到的后果
  • 原文地址:https://www.cnblogs.com/LQBlog/p/10697281.html
Copyright © 2011-2022 走看看