mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录

直接上图:

mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第1张图片

纯 Mybatis 操作时:

  • 解析mybatis-config.xml赋值mybatis的Configuration,扫描注册的 *.xml,生成 protected final Map mappedStatements; key为 全限定名加接口方法名,每个value为解析selectdelete标签对应的MappedStatement对象
  • 并扫描路径下对应mapper接口在mapperRegistry,其中包含属性 Map, MapperProxyFactory> knownMappers = new HashMap(); key 为对应接口class文件,value为MapperProxyFactory,构造函数对象赋值 mapperInterface
  • sqlSession.getMapper(TestMapper.class),传入对应mapper接口的 class,在 mapperRegistry获取对应的MapperProxyFactory其中有对应的类加载器,类接口,Invocation程序处理调用程序,因为 MapperProxy implements InvocationHandler,每一个MapperProxy实际为一个InvocationHandler,重写 invoke()方法,执行具体方法逻辑
  • 然后生成对应的 代理类,由代理类执行真是业务方法,在 MapperMethod,invoke()中,根据参数获取对应MappedStatement对应,传入Executor执行器,执行 具体jdbc,并封装返回结果集
  • MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(this.command.getName());
  • MapperProxyFactory { 映射器代理工厂

在Spring boot 中,注入 UserMapper userMapper;,其实就是注入具体的代理类,由代理执行具体方法。

  • 不可能裸注入接口,而没有具体实现撒

注意:

sqlSession.getMapper(TestMapper.class),是获取 mapperRegistry中对应的MapperProxyFactory,由

mapperProxyFactory.newInstance(sqlSession)

//构建对应,Invocation 调用处理类 MapperProxy
public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
}

//生成对应代理类
 protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(
        this.mapperInterface.getClassLoader(), 
        new Class[]{this.mapperInterface},
        mapperProxy);
}
public class MybatisUtil {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        InputStream inputStream = null;
        try {
        	//读取全局配置xml
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            //InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //解析xml,从跟节点 configuration 开始逐个取值,并赋值到 Configuration 对象,并且返回   DefaultSqlSessionFactory 对象。( 其中也包含 注册的 mapper.xml的解析 )
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        //this.build(parser.parse());
        // this.mapperElement(root.evalNode("mappers")); --> mapper.xml 解析,封装 MappedStatement对象
        // 存储在Configuration对象的mappedStatements属性中,mappedStatements 是一个HashMap,存储时key = 全限定类名 + 方法名,value = 对应的MappedStatement对象。
        //return new DefaultSqlSessionFactory(config);
        //this.parseConfiguration(this.parser.evalNode("/configuration"));
    }
	
	// 开启事务管理,创建执行器,返回 SqlSession 
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
	
	/*
	private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            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;
    } 
	 */
	

}

@org.junit.Test
public void example(){
    //sqlsession是线程不安全的,一次会话结束关闭资源
    SqlSession sqlSession = MybatisUtil.getSqlSession();

    TestMapper mapper = sqlSession.getMapper(TestMapper.class);
    List<Test> all = mapper.all();
    System.out.println(all);

    sqlSession.close();
}

// 通过动态代理实现, mapperMethod.execute(sqlSession, args); 实现逻辑处理
 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        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);
            }
        }
}


public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      //判断调用是是不是Object中定义的方法,toString,hashCode这类非。是的话直接放行。
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    } 
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
}

mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第2张图片
mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第3张图片

核心原理流程:

  • 读取全局配置xml,获取配置文件输入流,由 SqlSessionFactoryBuilder解析创建 SqlSessionFactory,其中包含 赋值 Configuration,以及解析注册的mapper.xml 并封装为MappedStatement(HashMap),为Configuration的一个属性值。
  • sqlSessionFactory.openSession() 开启获取一个sqlsession,创建事务管理器,Executor 执行器,返回一个sqlsesion对象
  • 具体执行 TestMapper mapper = sqlSession.getMapper(TestMapper.class),通过传入 具体业务mapper对象字节码,获取代理 MapperProxyFactory 代理工厂,以及当前 sqlseesion - > mapperProxyFactory.newInstance(sqlSession); 获取当前对象代理对象,并调用方法,执行时(动态代理)实现方法增强,mapperMethod.execute(sqlSession, args),最后由executor具体执行业务处理

Spring boot + Mybatis 时:

  • 整合步骤:
  1. 导入 mybatis-spring-boot-starter
  2. application.yml 配置 spring.datasource数据源,以及 mybatis.mapper-locations: classpath:xml/*.xml
  3. Springboot 启动类,添加@MapperScan("com.mapper"),mapper扫描 / 或 @Mapper标注mapper接口

只需要这三步,就可以开用如:userMapper.searchAll();

流程原理解析:

springboot自动装配,加载 /META-INFspring.factoriesproperties -> 加载org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration,-> MybatisAutoConfiguration 导入spring容器.

mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第4张图片
mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第5张图片

1.注解类标住@MapperScan("com.mapper") 扫描mapper时:
mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第6张图片
mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第7张图片
会通过配置的基础路径扫描全部的mapper接口,注入spring容器。

2.mapper接口标识@Mapper
mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第8张图片
MybatisAutoConfiguration 自动配置类中,AutoConfiguredMapperScannerRegistrar,会扫描标识了@Mapper的接口,注入容器。

SqlSessionFactory实例化;

  • 由于配置类的生效条件之一就是,datasource的注入。
  • mapper.xml 扫描,在yml中就配置了扫描路径. -> mapper-locations: classpath:xml/*.xml
  • sqlsessionFactory初始化,解析配置configuration,XMLMapperBuilder会解析mapperLocations下对应mapper.xml文件
    mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第9张图片
    7
    mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第10张图片
    mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第11张图片

具体执行: 该有的都有了,在userMapper.searchAll();时,跟纯mybaits时差不多了。

  • 通过代理对象执行方法,并走方法增加具体执行。
    mybatis 原理流程图示、Springboot mybaits 梳理 -分析记录_第12张图片

你可能感兴趣的:(笔记,后端框架,mybatis,spring,boot)