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() 方法我们可以看到

Java 启动的时候 MyBatis plus卡很久_配置文件


在去 parser.parse() 方法中可以看到

Java 启动的时候 MyBatis plus卡很久_sql_02


然后出去 还有一个 this.build()方法会看到这样的,加载一个默认的sqlSession工厂对象,然后到下面,工厂被创建出来。

Java 启动的时候 MyBatis plus卡很久_jdk动态代理_03


Java 启动的时候 MyBatis plus卡很久_sql_04

第二步获取单个的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;
    }

Java 启动的时候 MyBatis plus卡很久_java_05

上面我们就拿到了 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);
            }
        }
    }

Java 启动的时候 MyBatis plus卡很久_jdk动态代理_06


然后就拿到了 mapper 的代理对象 ,然后在通过 mapper 接口去调用相应的 方法

Java 启动的时候 MyBatis plus卡很久_mybatis_07

然后这个过程就基本结束了,在我看来是这样的,可能很多地方分析的不到位,或者存在一定的知识缺失,欢迎大家指正。在面试的时候,如果面试官问有没有看过源码,可以选择mybatis去看,他的执行过程是挺清楚的,遇到自己解决不了的问题就 多问百度 一定会有大佬为你解决问题的,哈哈,这个过程我感觉可以做为面试时,回答mybatis启动流程的答案,从不同的层面去回答,这样也不会把自己说的混乱