zoukankan      html  css  js  c++  java
  • mybatis源码1.1:Configuration,SqlSessionFactory对象的创建

    首先了解一下mybatis的重点对象Configuration对象

    Configuration对象在mybatis允许流程中是全局唯一的,先看一下Configuration对象,默认构造方法中进行一些默认参数的配置,往后就是解析配置文件,添加配置信息到Configuration对象中了

        public Configuration() {
            this.safeResultHandlerEnabled = true;
            this.multipleResultSetsEnabled = true;
            this.useColumnLabel = true;
            this.cacheEnabled = true;
            this.useActualParamName = true;
            this.localCacheScope = LocalCacheScope.SESSION;
            this.jdbcTypeForNull = JdbcType.OTHER;
            this.lazyLoadTriggerMethods = new HashSet(Arrays.asList("equals", "clone", "hashCode", "toString"));
            this.defaultExecutorType = ExecutorType.SIMPLE;
            this.autoMappingBehavior = AutoMappingBehavior.PARTIAL;
            this.autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
            this.variables = new Properties();
            this.reflectorFactory = new DefaultReflectorFactory();
            this.objectFactory = new DefaultObjectFactory();
            this.objectWrapperFactory = new DefaultObjectWrapperFactory();
            this.lazyLoadingEnabled = false;
            this.proxyFactory = new JavassistProxyFactory();
            this.mapperRegistry = new MapperRegistry(this);
            this.interceptorChain = new InterceptorChain();
            this.typeHandlerRegistry = new TypeHandlerRegistry();
            this.typeAliasRegistry = new TypeAliasRegistry();
            this.languageRegistry = new LanguageDriverRegistry();
            this.mappedStatements = (new Configuration.StrictMap("Mapped Statements collection")).conflictMessageProducer((savedValue, targetValue) -> {
                return ". please check " + savedValue.getResource() + " and " + targetValue.getResource();
            });
            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");
            this.loadedResources = new HashSet();
            this.sqlFragments = new Configuration.StrictMap("XML fragments parsed from previous mappers");
            this.incompleteStatements = new LinkedList();
            this.incompleteCacheRefs = new LinkedList();
            this.incompleteResultMaps = new LinkedList();
            this.incompleteMethods = new LinkedList();
            this.cacheRefMap = new HashMap();
          //默认别名配置
            this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
            this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
            this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
            this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
            this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
            this.typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
            this.typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
            this.typeAliasRegistry.registerAlias("LRU", LruCache.class);
            this.typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
            this.typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
            this.typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
            this.typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
            this.typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
            this.typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
            this.typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
            this.typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
            this.typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
            this.typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
            this.typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
            this.typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
            this.typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
            this.typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
            this.languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
            this.languageRegistry.register(RawLanguageDriver.class);
        }
    View Code

    创建好测试类,其他mybatis配置文件,pom文件,实体类,mapper接口,mapper.xml文件这里忽略

    public class MyBatisRunTest {
    
        @Test
        public void testProcess() throws Exception{
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sessionFactory = builder.build(resourceAsStream);//断点,debug执行
            SqlSession sqlSession = sessionFactory.openSession(true);
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.selectById(1);
            System.out.println(mapper.getClass());
            System.out.println(user);
    
        }
    }

    进入SqlSessionFactoryBuilder类中的build方法,该方法又调用自身重载方法

        public SqlSessionFactory build(InputStream inputStream) {
            return this.build((InputStream)inputStream, (String)null, (Properties)null);
        }
        public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
            SqlSessionFactory var5;
            try {
                XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
                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) {
            return new DefaultSqlSessionFactory(config);
        }

    抽象类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();
        }
    //此处省略一大堆代码
    }
    View Code

    接着创建了XMLConfigBuilder对象,XMLConfigBuilder中包含了解析配置文件的方法,并且把配置文件中获取的配置都设置到Configuration对象中,XMLConfigBuilder继承了抽象类BaseBuilder

        
      //调用该构造方法,该构造方法又调用下面的构造方法
      public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
            this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
        }
    
        private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
         //调用BaseBuilder的构造方法,创建一个Configuration对象传入
            super(new Configuration());
            this.localReflectorFactory = new DefaultReflectorFactory();
            ErrorContext.instance().resource("SQL Mapper Configuration");
            this.configuration.setVariables(props);
            this.parsed = false;
            this.environment = environment;
            this.parser = parser;
        }
    View Code
    接下里XMLConfigBuilder调用parse方法进行解析我们的mybatis配置文件,从configuration节点开始进行解析
    public Configuration parse() {
            if (this.parsed) {
                throw new BuilderException("Each XMLConfigBuilder can only be used once.");
            } else {
                this.parsed = true;
                this.parseConfiguration(this.parser.evalNode("/configuration"));
                return this.configuration;
            }
        }
    View Code
    private void parseConfiguration(XNode root) {
            try {
           //解析properties标签,properties标签是用来接着外部properties配置文件的,最终设置到Configuration对象中,如:常见的jdbc.properties
                this.propertiesElement(root.evalNode("properties"));
                Properties settings = this.settingsAsProperties(root.evalNode("settings"));
                this.loadCustomVfs(settings);
                this.loadCustomLogImpl(settings);
           //添加开发着定义的别名配置到Configuration中
                this.typeAliasesElement(root.evalNode("typeAliases"));
                this.pluginElement(root.evalNode("plugins"));
                this.objectFactoryElement(root.evalNode("objectFactory"));
                this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
                this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
                this.settingsElement(settings);
                this.environmentsElement(root.evalNode("environments"));
                this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
                this.typeHandlerElement(root.evalNode("typeHandlers"));
           //mapper的解析
                this.mapperElement(root.evalNode("mappers"));
            } catch (Exception var3) {
                throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
            }
        }
    View Code
    这里先查看this.mapperElement方法
    该方法时处理mapper的解析,层层调用,最终调用MapperRegistry中的addMappers方法,最终是添加到Configuration中的MapperRegistry对象中的Map<Class<?>, MapperProxyFactory<?>> knownMappers中
    key为当前遍历的mapper接口的Class对象,value为MapperProxyFactory对象,
        public <T> void addMapper(Class<T> type) {
         //判断是否是接口
            if (type.isInterface()) {
            //是否已经添加该mapper接口的Class对象
                if (this.hasMapper(type)) {
                    throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
                }
    
                boolean loadCompleted = false;
    
                try {
                    this.knownMappers.put(type, new MapperProxyFactory(type));
                    MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
                    parser.parse();
                    loadCompleted = true;
                } finally {
                    if (!loadCompleted) {
                        this.knownMappers.remove(type);
                    }
    
                }
            }
    
        }
    
        public Collection<Class<?>> getMappers() {
            return Collections.unmodifiableCollection(this.knownMappers.keySet());
        }
    
        public void addMappers(String packageName, Class<?> superType) {
          //扫面指定包下的mapper接口文件,设置到ResolverUtil中的Set集合中,值为mapper接口的Class对象
            ResolverUtil<Class<?>> resolverUtil = new ResolverUtil();
            resolverUtil.find(new IsA(superType), packageName);
    
    
            Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
            Iterator var5 = mapperSet.iterator();
    
         //对扫描的的mapper接口集合进行遍历
            while(var5.hasNext()) {
                Class<?> mapperClass = (Class)var5.next();
            //调用上边的addMapper重载方法
                this.addMapper(mapperClass);
            }
    
        }
      
        public void addMappers(String packageName) {
            this.addMappers(packageName, Object.class);
        }
    View Code

    配置文件的解析,最后返回Configuration对象,用来构建SqlSessionFactory,也就是DefaultSqlSessionFactory,最后返回

        public SqlSessionFactory build(Configuration config) {
            return new DefaultSqlSessionFactory(config);
        }

     这里就简单的了解了SqlSessionFactory的创建,大致就是流程就是,

    1,创建SqlSessionFactoryBuilder对象,这里简称sfb

    2,sfb中创建XMLConfigurationBuilder对象,XmlConfigurationBuilder创建一个默认配置的Configuration对象,XMLConfigurationBuilder继承了BaseBuilder,里面有Configuration对象的引用

    3,通过XMLConfigurationBuilder对象进行配置文件的解析,把配置信息添加到Configuration对象中去,这里我简单查看了mapper的解析,这里还包括很多解析,如:别名,typeHandler········,最后返回Configuration对象

    4,最后得到configuration对象后,sfb通过build方法创建SqlSessionFactory对象

     附上最后编辑时间    2020-04-12 18:45

    今天暂时就到这,后续会继续阅读下去,这里有什么错误,日后理解更充分后进行再修改,

    今天突然收到面试消息,明天早上11点,从来都没有准备过面试,现在准备临阵磨枪,希望明天好运,god bless me ! 

  • 相关阅读:
    jquery怎么实现跨域的访问呢?与别人提供的接口连接
    服务器返回数组,data[0]得到的总是不对?如何处理?
    ajax 如何实现页面跳转
    问答精华-IntelliJ IDEA快捷键大全
    setinterval在jQuery里面是怎么使用的。
    background 、backgroundcolor、background-color 我怎么有点分不清了??
    视频最后用使用了function(i,ot)一笔带过,但我看不懂i和ot这2个参数的具体值是怎么获取得到的,能不能说一下参数传递过程?
    3张大图片自动播放
    图片自动加载
    用jQuery之后,之前javascript的一些方法就不能用了吗
  • 原文地址:https://www.cnblogs.com/a-small-lyf/p/12678248.html
Copyright © 2011-2022 走看看