mybatis源码1.1:Configuration,SqlSessionFactory对象的创建
首先了解一下mybatis的重点对象Configuration对象
Configuration对象在mybatis允许流程中是全局唯一的,先看一下Configuration对象,默认构造方法中进行一些默认参数的配置,往后就是解析配置文件,添加配置信息到Configuration对象中了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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); }
创建好测试类,其他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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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(); } //此处省略一大堆代码 }
接着创建了XMLConfigBuilder对象,XMLConfigBuilder中包含了解析配置文件的方法,并且把配置文件中获取的配置都设置到Configuration对象中,XMLConfigBuilder继承了抽象类BaseBuilder
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//调用该构造方法,该构造方法又调用下面的构造方法 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; }
接下里XMLConfigBuilder调用parse方法进行解析我们的mybatis配置文件,从configuration节点开始进行解析
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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; } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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); } }
这里先查看this.mapperElement方法
该方法时处理mapper的解析,层层调用,最终调用MapperRegistry中的addMappers方法,最终是添加到Configuration中的MapperRegistry对象中的Map<Class<?>, MapperProxyFactory<?>> knownMappers中
key为当前遍历的mapper接口的Class对象,value为MapperProxyFactory对象,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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); }
配置文件的解析,最后返回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 !