SqlSessionFactoryBuilder
SqlSessionFactoryBuilder
使用了Builder
模式用来创建SqlSessionFactory
;
创建 SqlSessionFactory
对象两种方式:
- 使用
Configuration
对象(mybaits全局配置对象),创建一个默认的DefaultSqlSessionFactory
对象; - 通过配置文件
*.xml
文件流、environment
、properties
等解析为Configuration
对象,然后通过Configuration
对象,创建默认的DefaultSqlSessionFactory
对象;
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
SqlSessionManager
-
SqlSessionManager
实现了SqlSessionFactory
、SqlSession
接口,重写了这两个接口的所有方法;
public class SqlSessionManager implements SqlSessionFactory, SqlSession
image.png
- 包含两个成员变量
sqlSessionFactory
、sqlSessionProxy
,通过newInstance()
方法调用构造方法进行赋值;
public static SqlSessionManager newInstance(Reader reader) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
}
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
-
sqlSessionProxy
为一个代理对象,通过Java
反射技术生成代理对象。
private class SqlSessionInterceptor implements InvocationHandler {
public SqlSessionInterceptor() {
// Prevent Synthetic Access
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
if (sqlSession != null) {
try {
return method.invoke(sqlSession, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} else {
try (SqlSession autoSqlSession = openSession()) {
try {
final Object result = method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return result;
} catch (Throwable t) {
autoSqlSession.rollback();
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
}
}
-
SqlSeesion
接口定义了close()
、commit()
、rollback()
、clearCache()
等方法,为了操作同一个SqlSeesion
对象,引入了ThreadLocal
变量,通过localSqlSession
确保操作同一个SqlSession
,保证了线程安全。
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
//通过此方法,对localSqlSession赋值
public void startManagedSession() {
this.localSqlSession.set(openSession());
}
BaseBuilder
BaseBuilder
是一个基础抽象类,定义了一些通用方法,有多个具体实现类;成员变量包括:解决数据类型别名的注册器 typeAliasRegistry
,及处理 JDBC 类型和 Java 数据类型对应的、类型处理转换器注册中心 typeHandlerRegistry
,;还有一些简单的工具方法;
包含3个成员变量:
-
Configuration
mybatis 全局配置对象; -
TypeAliasRegistry
类型别名注册中心,处理各种类型别名; -
TypeHandlerRegistry
类型处理器注册中心,处理各种TypeHandler ;
多个具体实现类图,介绍其中的XMLConfigBuilder
image.png
XMLConfigBuilder
XMLConfigBuilder
是一个读取并解析 mybatis-config.xml 配置的文件的类;
s
成员变量:
private boolean parsed; // 标识是否已经解析 mybats-config.xml 配置丈件
private final XPathParser parser; //用于解析 mybatis config xml 配置文件的 XPathParser 对象
private String environment; //标识<environment>配置的名称,默认读取<environment> 标签的 default 属性
//ReflectorFactory 负责创建和缓存 Reflector 对象
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
使用
在 SqlSessionFactoryBuilder 中创建 XMLConfigBuilder 对象,并解析 mybatis-config.xml 文件,返回全局的 Configuration 对象;
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// 解析配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 构建 SqlSessionFactory 对象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
方法
- parse() 解析 mybatis-config 文件,并返回全局 Configuration 对象
// 解析 mybatis-config 文件,并返回全局 Configuration 对象
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//在 mybatis-config xml 配置文件中查找<configuration>节点,并开始解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
- parseConfiguration(XNode root) 解析 mybatis-config.xml 文件中的各个节点
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
//<properties resource="org/apache/ibatis/databases/blog/blog-derby.properties"/>
//解析<properties>节
propertiesElement(root.evalNode("properties"));
// <settings>
// <setting name="cacheEnabled" value="true"/>
// <setting name="lazyLoadingEnabled" value="false"/>
// </settings>
//解析<settings>节点
Properties settings = settingsAsProperties(root.evalNode("settings"));
// TODO: 2020/8/4 vfs 虚拟文件系统
loadCustomVfs(settings); // 设置 vfsimpl 字段
loadCustomLogImpl(settings);
//解析<typeAliases>节点
typeAliasesElement(root.evalNode("typeAliases"));
//解析<plugins>节
pluginElement(root.evalNode("plugins"));
//解析<objectFactory>节点
objectFactoryElement(root.evalNode("objectFactory"));
//解析 <objectWrapperFactory> 节点
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//解析<reflectorFactory>节点
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 解析各种设置,在 mybatis 环境中生效
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
//解析<environments>节点
environmentsElement(root.evalNode("environments"));
//解析<databaseidProvider>节点
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//解析<typeHandlers>节点
typeHandlerElement(root.evalNode("typeHandlers"));
//解析<mappers>节点
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
- 解析中具体使用到的方法和注解说明
// 检测 setting 属性是否是 Configuration 中指定的,包含 setter 方法, 就是指定的 Configuration 属性
// 使用 MetaClass 检测 key 定的属性在 configuration 类中是否有对应 setter 方法的步骤。
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
Properties props = context.getChildrenAsProperties();
// Check that all settings are known to the configuration class
// 检查 setting 设置的参数,是否是指定的,并可被解析的
// 创建 Configuration 类的元信息包装类,localReflectorFactory 为 DefaultReflectorFactory 新建的对象;
// metaConfig 为短暂的方法生命周期对象,近在此方法中临时创建,并近存活于此方法中;
// 检测 Configuration 是否定义了 key 指定属性相应的 setter 方法
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
for (Object key : props.keySet()) {
if (!metaConfig.hasSetter(String.valueOf(key))) {
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
return props;
}
private void loadCustomVfs(Properties props) throws ClassNotFoundException {
String value = props.getProperty("vfsImpl");
if (value != null) {
String[] clazzes = value.split(",");
for (String clazz : clazzes) {
if (!clazz.isEmpty()) {
@SuppressWarnings("unchecked")
Class<? extends VFS> vfsImpl = (Class<? extends VFS>)Resources.classForName(clazz);
configuration.setVfsImpl(vfsImpl);
}
}
}
}
private void loadCustomLogImpl(Properties props) {
Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
configuration.setLogImpl(logImpl);
}
/**
* 解析类的别名
<typeAliases>
<typeAlias alias="BlogAuthor" type="org.apache.ibatis.domain.blog.Author"/>
<typeAlias type="org.apache.ibatis.domain.blog.Blog"/>
<typeAlias type="org.apache.ibatis.domain.blog.Post"/>
<package name="org.apache.ibatis.domain.jpetstore"/>
</typeAliases>
*/
private void typeAliasesElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
// 如果包含 package,解析 package 下类,进行别名注册
// 处理<package >节点
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
// 通过 TypeAliasRegistry 扫描指定包中所有的类,并解析@Alias 注解,完成别名注册
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
String alias = child.getStringAttribute("alias"); // 获取指定的别名
String type = child.getStringAttribute("type"); // 获取别名对应的类型
try {
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
typeAliasRegistry.registerAlias(clazz); // 扫描 @Alias 完成注册 ,完成注册
} else {
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
// 以通过添加自定义插件在 SQL 语句执行过程中的某点进行拦截。 MyBatis 中的自定义插件只需实现 Interceptor 接口,并通过注解指定想
// 要拦截的方法签名即可
/**
* <plugins>
* <plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
* <property name="pluginProperty" value="100"/>
* </plugin>
* </plugins>
* @param parent
* @throws Exception
*/
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
// 创建插件实例,插件是 Interceptor 的具体实现
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
// 设置插件的属性
interceptorInstance.setProperties(properties);
// 设置插件到拦截器链中
configuration.addInterceptor(interceptorInstance);
}
}
}
/**
* <objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory">
* <property name="objectFactoryProperty" value="100"/>
* </objectFactory>
* @param context
* @throws Exception
*/
// 解析 objectFactory 节点, objectFactory 创建对象的工厂
// 可以通过添加自定义 ObjectFactory 实现类、ObjectWrapperFactory 实现类、ReflectorFactory 实现类对 Mybatis 进行扩展
private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties properties = context.getChildrenAsProperties();
ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance(); // 创建 objectFactory 对象
factory.setProperties(properties); // 设置对象属性
configuration.setObjectFactory(factory); // 反写 configuration 对象中的 objectFactory 属性
}
}
/**
* 解析 <objectWrapperFactory> 节点
* @param context
* @throws Exception
*/
private void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).getDeclaredConstructor().newInstance();
configuration.setObjectWrapperFactory(factory);
}
}
/**
* 解析<reflectorFactory>节点
* @param context
* @throws Exception
*/
private void reflectorFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).getDeclaredConstructor().newInstance();
configuration.setReflectorFactory(factory);
}
}
//解析properties节点
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//得到所有的孩子属性;
Properties defaults = context.getChildrenAsProperties();
//parse only one resource element : resource or url
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
// ...与 Configurat on 对象中 variables 集合合并(略)
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
//设置 解析器 variables; 在后面的解析过程中,会使用该 Properties 对象中的信息替换占位符。
parser.setVariables(defaults);
//更新 configuration 的 variables 变量
configuration.setVariables(defaults);
}
}
/**
* 解析全局配置,并应用到 mybatis 全局变量,使配置生效
* @param props
*/
private void settingsElement(Properties props) {
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setDefaultResultSetType(resolveResultSetType(props.getProperty("defaultResultSetType")));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
}
/**
* <environments default="development">
* <environment id="development">
* <transactionManager type="JDBC">
* <property name="" value="" />
* </transactionManager>
* <dataSource type="UNPOOLED">
* <property name="driver" value="org.hsqldb.jdbcDriver" />
* <property name="url" value="jdbc:hsqldb:mem:localtime" />
* <property name="username" value="sa" />
* </dataSource>
* </environment>
* </environments>
*
* @param context
* @throws Exception
*/
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
//未指定 XMLConfigBuilder environment 字段,则使用 default 性指定的 <environment>
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); // 创建 TransactionFactory
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); // 创建 DataSourceFactory
DataSource dataSource = dsFactory.getDataSource(); // 创建 DataSource
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build()); // 创建 Environment,并反写 configuration 对象
}
}
}
}
/**
* <databaseIdProvider type="DB_VENDOR">
* <property name="Apache Derby" value="derby"/>
* </databaseIdProvider>
* @param context
* @throws Exception
*/
private void databaseIdProviderElement(XNode context) throws Exception {
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
String type = context.getStringAttribute("type");
// awful patch to keep backward compatibility
if ("VENDOR".equals(type)) { // 为了保证兼容性,修改 type 取值
type = "DB_VENDOR";
}
Properties properties = context.getChildrenAsProperties();
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
databaseIdProvider.setProperties(properties);
}
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
// 根据前面确定的 DataSource 确定当前使用的数据库产品,得到不同厂商数据库Id
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
configuration.setDatabaseId(databaseId);
}
}
/**
* 根据 配置文件中的节点,创建 TransactionFactory 对象
* @param context
* @return
* @throws Exception
*/
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
/**
* 根据 配置文件中的节点,创建 DataSourceFactory 对象
* @param context
* @return
* @throws Exception
*/
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
/**
* 解析<typeHandlers>节点
* @param parent
*/
private void typeHandlerElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
} else {
String javaTypeName = child.getStringAttribute("javaType");
String jdbcTypeName = child.getStringAttribute("jdbcType");
String handlerTypeName = child.getStringAttribute("handler");
Class<?> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
/**
* 解析实体 mapper 文件;
* <mappers>
* <mapper resource="org/apache/ibatis/builder/BlogMapper.xml"/>
* <mapper url="file:./src/test/java/org/apache/ibatis/builder/NestedBlogMapper.xml"/>
* <mapper class="org.apache.ibatis.builder.CachedAuthorMapper"/>
* <package name="org.apache.ibatis.builder.mapper"/>
* </mappers>
* @param parent
* @throws Exception
*/
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) { // <package >子节点
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
// 获取<mapper >节点的 resource url class 属性,这三个属性互斥
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
// 如果<mapper >节点指定了 resource 或是 url 属性,则创建 XMLMapperBuilder 对象
// 并通过该对象解析 resource 或是 url 属性指定的 Mapper 配置文件
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
// 解析 mapper 节点
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
// 如果<mapper>节点指定了 class 属性,则 MapperRegistry 注册该 Mapper 接口
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
/**
* 检测是否是,指定的环境
* @param id
* @return
*/
private boolean isSpecifiedEnvironment(String id) {
if (environment == null) {
throw new BuilderException("No environment specified.");x
} else if (id == null) {
throw new BuilderException("Environment requires an id attribute.");
} else if (environment.equals(id)) {
return true;
}
return false;
}
创建SqlSessionFactory
经过上面的解析和加载过程,已经创建了 SqlSessionFactory 对象,并初始化了 Configuration 全局配置对象,最后返回一个 SqlSessionFactory 供 SqlSessionManager 使用。然后通过构造方法创建了 SqlSessionManager 对象。
// 通过 newInstance() 方法创建 SqlSessionManager 对象
public static SqlSessionManager newInstance(Reader reader) {
// 创建 SqlSessionFactory 对象,作为成员变量
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
// SqlSessionManager 构造方法
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
// 使用动态代理的方式创建 SqlSession 的代理对象
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
}
启动流程
- 解析 mybatis-congfig.xml 配置文件
- 解析各个实体 mapper.xml 文件
- 解析配置文件创建全局配置对象 Configuration 对象
- 通过 Configuration 成员变量,构建 SqlSessionFactory 对象
- 通过 SqlSessionFactory.openSession() 创建 SqlSession 对象
- 创建 SqlSession 对象同时,也创建了 Transaction、Executor 等对象
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获取 mybatis-config.xml 配置文件中配置的 Environment 对象
final Environment environment = configuration.getEnvironment();
// 获取 TransactionFactory
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 创建 Transaction 对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建 Executor 对象
final Executor executor = configuration.newExecutor(tx, execType);
// 创建 DefaultSqlSession 对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
// 关闭 Transaction
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
- 还会通过 Configuration 对象创建 StatementHandler、parameterHandler、resultSetHandler 对象
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
ParameterHandler parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
ResultSetHandler resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
至此为止 MyBatis 已经启动完毕,创建了 SqlSession、Executor 、StatementHandler、parameterHandler、resultSetHandler等关键对象,为后续数据查询奠定了基础。
网友评论