mybatis启动分析
第一步加载配置文件
// SqlSessionFactory 工厂
private static SqlSessionFactory sessionFactory = null;
// sqlSession 实际操作对象
private static SqlSession sqlSession = null;
static {
try {
//以流的方式加载配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//解析io流获得一个session工厂
sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
进入两次 build() 方法我们可以看到
在去 parser.parse() 方法中可以看到
然后出去 还有一个 this.build()方法会看到这样的,加载一个默认的sqlSession工厂对象,然后到下面,工厂被创建出来。
第二步获取单个的SqlSession(执行器)对象
/**
* 获取session
* @return
*/
public static SqlSession getSqlSession(){
//获取session
sqlSession = sessionFactory.openSession();
return sqlSession;
}
进入 openSession 方法中,可以看到三个参数,第一个记载默认配置,第二个设置事务隔离级别,第三个是否开启事务自动提交
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
再找到 this.openSessionFromDataSource() 方法
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
//定义事务
Transaction tx = null;
DefaultSqlSession var8;
try {
//mybatis配置文件中所有信息都封装到Configuration中,获取环境 Environment中有id、datasource、transactionFactory三个属性
Environment environment = this.configuration.getEnvironment();
//配置事务工厂
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
//根据工厂创建事物对象,参数很清楚是什么意思,一个数据源,一个隔离级别,一个是否自动提交
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//开始创建执行器
Executor executor = this.configuration.newExecutor(tx, execType);
//默认executor是CachingExecutor
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
上面我们就拿到了 sessionFactory 工厂和 SqlSession 对象(在这里,mybatis使用了 工厂设计 模式)
第三步 加载 mapper 文件,执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
使用调试模式,大概走 三次 getMapper 后会 到达 这个方法
简单分析一下可以得到,他通过 反射,使用jdk动态代理创建一个代理工厂( jdk动态代理 代理接口,mybatis是通过mapper接口与xml文件进行映射,所以使用的jdk动态代理 )创建一个确定类的 mapper 代理工厂,然后进行一些逻辑的判断,然后再去 newInstance 创建一个mapper 实例
补充一些东西,jdk动态代理代理接口,cglib动态代理,代理的是对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// mapper 代理 工厂 (这里使用的jdk动态代理)
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
// 如果主配置文件中没有进行xxxMapper.xml文件的映射,会出现这个问题
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
//继续走 进这个方法
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
然后就拿到了 mapper 的代理对象 ,然后在通过 mapper 接口去调用相应的 方法
然后这个过程就基本结束了,在我看来是这样的,可能很多地方分析的不到位,或者存在一定的知识缺失,欢迎大家指正。在面试的时候,如果面试官问有没有看过源码,可以选择mybatis去看,他的执行过程是挺清楚的,遇到自己解决不了的问题就 多问百度 一定会有大佬为你解决问题的,哈哈,这个过程我感觉可以做为面试时,回答mybatis启动流程的答案,从不同的层面去回答,这样也不会把自己说的混乱