// # 1.读取配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");// # 2.创立SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// # 3.通过sqlSessionFactory创立SqlSessiontry (SqlSession session = sqlSessionFactory.openSession()) { // # 4.通过SqlSession获取Mapper,并查问 BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101);}
以上是Mybatis官网的demo,这次DB查问操作根本分成了上述4个步骤。
那么问题来了:在一次DB查问过程,mybatis框架具体做了什么?
间接给出论断:
1.读取mybatis-config.xml并解析,将全副配置信息和各种默认配置加载到Configuration中,蕴含:数据源信息(分装在Environment)、类型处理器、类型别名、mapper代理工厂等。
Configuration是SqlSessionFactory的重要属性。2.通过SqlSessionFactory创立transaction、executor、sqlSession。
3.通过sqlSession获取mapper,实质是通过mapper代理工厂创立mapper代理。mapper的crud办法理论执行的是MapperProxy的相干办法。
在这些办法中,sql会交由executor执行,而executor最终会调用jdbc的statement。
接下来通过源码剖析demo中的四步。
一、读取配置文件
// == A.mybatis配置文件转换成streamInputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
配置文件读取局部没什么可说的,无非把File转换成IO流。
咱们把眼光聚焦于mybatis-config.xml
文件自身。
<configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/BlogMapper.xml"/> </mappers></configuration>
能够看到,最外层是一个<configuration>
标签,外面可退出很多配置,如:
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
environments(环境配置)
environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
理解这些就能够了,前面几步才是重点。
二、创立SqlSessionFactory
// == B.初始化Configuration,并加载各类默认配置(次要是类型转换器和别名映射)SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream)org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream, java.lang.String, java.util.Properties)public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { // ## 1.解析 mybatis-config.xml,同时创立 Configuration 对象 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // ## 2.解析XML,最终返回一个 DefaultSqlSessionFactory return build(parser.parse());}
1.解析 mybatis-config.xml
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) { // 构造函数实现了Configuration的初始化,并将configuration的两个重要属性传递过去 super(new Configuration()); ⬇⬇⬇⬇⬇ this.configuration = configuration; this.typeAliasRegistry = this.configuration.getTypeAliasRegistry(); this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry(); ⬆⬆⬆⬆⬆ super(new Configuration());}
察看传递过去的两个属性
### org.apache.ibatis.session.Configuration类 ###// 类型解决注册器protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);// 类型别名注册器protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
别离查看它们的构造函数。
- 类型解决注册器TypeHandlerRegistry
为特定类型创立处理器
org.apache.ibatis.type.TypeHandlerRegistry#TypeHandlerRegistry{ register(Boolean.class, new BooleanTypeHandler()); register(JdbcType.BIT, new BooleanTypeHandler()); register(Byte.class, new ByteTypeHandler()); register(JdbcType.TINYINT, new ByteTypeHandler()); register(Short.class, new ShortTypeHandler()); register(JdbcType.SMALLINT, new ShortTypeHandler()); }
- 类型别名注册器TypeAliasRegistry
为根本类型起别名
org.apache.ibatis.type.TypeAliasRegistry#TypeAliasRegistry{ registerAlias("byte", Byte.class); registerAlias("long", Long.class); registerAlias("short", Short.class); registerAlias("int", Integer.class); }
- 再察看Configuration的构造函数
org.apache.ibatis.session.Configuration#Configuration()// 构造函数做各种别名设置public Configuration() { typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class); typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class); typeAliasRegistry.registerAlias("LRU", LruCache.class); typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class); typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class); }
2.解析XML
这一步做了很多事,篇幅关系不能全副剖析。
org.apache.ibatis.builder.xml.XMLConfigBuilder#parseorg.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfigurationprivate void parseConfiguration(XNode root) { // 别名解析 typeAliasesElement(root.evalNode("typeAliases")); // 注册插件(过滤器,如PageHelper) pluginElement(root.evalNode("plugins")); // 对象工厂解析 objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); // 属性赋值(设置默认属性) settingsElement(settings); { configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true)); configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false)); configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE"))); configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION"))); } // 初始化environment,设置事务处理工厂、数据源 environmentsElement(root.evalNode("environments")); { TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); DataSource dataSource = dsFactory.getDataSource(); Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); } databaseIdProviderElement(root.evalNode("databaseIdProvider")); // 自定义类型转换器 typeHandlerElement(root.evalNode("typeHandlers")); // ### 解析mapper文件 mapperElement(root.evalNode("mappers"));}
重点看一下“解析mapper文件”局部:
org.apache.ibatis.session.Configuration#addMappers(java.lang.String)org.apache.ibatis.binding.MapperRegistry#addMappers(java.lang.String)org.apache.ibatis.binding.MapperRegistry#addMappers(java.lang.String, java.lang.Class<?>)// == 寄存Mapper(代理)工厂org.apache.ibatis.binding.MapperRegistry#addMapper{ knownMappers.put(type, new MapperProxyFactory<>(type)); }
最终会将Mapper代理工厂寄存在一个map汇合中,把“mapper定义的接口类”作为key。
三、通过sqlSessionFactory创立SqlSession
// == D. 创立session,DefaultSqlSessionSqlSession session = sqlSessionFactory.openSession()org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource{ final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 创立Executor,默认SimpleExecutor final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit);}
最终创立的是DefaultSqlSession,它封装了configuration和executor。
四、通过SqlSession获取Mapper,并查问
// == E. 获取mapper,通过MapperProxyFactory创立代理对象BlogMapper mapper = session.getMapper(BlogMapper.class);org.apache.ibatis.session.defaults.DefaultSqlSession#getMapperorg.apache.ibatis.binding.MapperRegistry#getMapper{ final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); return mapperProxyFactory.newInstance(sqlSession); org.apache.ibatis.binding.MapperProxyFactory #newInstance(org.apache.ibatis.binding.MapperProxy<T>) { // java形式创立代理对象 Proxy.newProxyInstance( mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }}
最终失去的mapper,其实是一个由MapperProxyFactory创立的代理;而代理类的InvocationHandler指向了MapperProxy。
那么咱们间接查看MapperProxy的invoke办法就好了。
// == F. 办法执行,会进入InvocationHandler(MapperProxy)的invoke办法Blog blog = mapper.selectBlog(101);org.apache.ibatis.binding.MapperProxy#invokeorg.apache.ibatis.binding.MapperMethod#execute{ // == 按操作类型辨别 case UPDATE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult( ## update执行 sqlSession.update(command.getName(), param)); break; } case DELETE: ... case SELECT: ...}
咱们以update为例,察看它的具体执行
update执行
org.apache.ibatis.session.defaults.DefaultSqlSession#update(java.lang.String, java.lang.Object)update(String statement, Object parameter) { MappedStatement ms = configuration.getMappedStatement(statement); // == 真正的执行动作在executor中 return executor.update(ms, wrapCollection(parameter));}
org.apache.ibatis.executor.BaseExecutor#update// 查看默认的SimpleExecutor实现org.apache.ibatis.executor.SimpleExecutor#doUpdatepublic int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; Configuration configuration = ms.getConfiguration(); // 封装成StatementHandler StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); // 筹备了Statement(曾经是jdbc逻辑) stmt = prepareStatement(handler, ms.getStatementLog()); // == 最终执行 return handler.update(stmt);}// 最终执行咱们仍然查看SimpleStatementHandler,发现就是相熟的jdbc statement执行sql逻辑org.apache.ibatis.executor.statement.SimpleStatementHandler#update{ statement.execute(sql);}
select执行
文章开始时,咱们的打算是剖析一次select执行
其实select与update的执行过程差不多,最终都会靠jdbc的statement执行。最大的差别在于select能够用到缓存,也就是人们常说的mybatis的一、二级缓存。
这部分内容放在下篇文章剖析。
附录
P6-P7常识合辑