美文网首页
mybatis源码1-spring管理

mybatis源码1-spring管理

作者: modou1618 | 来源:发表于2019-01-18 07:49 被阅读0次

一 dao接口扫描

1.1 注解MapperScan

  • @Import({MapperScannerRegistrar.class}) 注解MapperScan
  • ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()中对@Import注解进行处理。
  • 调用MapperScannerRegistrar实现接口ImportBeanDefinitionRegistrar的方法registerBeanDefinitions
  • 解析注解参数
说明
value 扫描目标包
basePackages 扫描目标包
basePackageClasses 扫描目标包
annotationClass 只扫描目标包里有该注解的类
markerInterface 只扫描目标包里父类接口为该接口的
sqlSessionTemplateRef 工厂类引用
sqlSessionFactoryRef 工厂类引用
  • 初始化ClassPathMapperScanner,开始包扫描scanner.doScan()
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    if(this.resourceLoader != null) {
        scanner.setResourceLoader(this.resourceLoader);
    }

    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if(!Annotation.class.equals(annotationClass)) {
        scanner.setAnnotationClass(annotationClass);
    }

    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if(!Class.class.equals(markerInterface)) {
        scanner.setMarkerInterface(markerInterface);
    }

    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if(!BeanNameGenerator.class.equals(generatorClass)) {
        scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
    }

    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
    List<String> basePackages = new ArrayList();
    String[] arr$ = annoAttrs.getStringArray("value");
    int len$ = arr$.length;

    int i$;
    String pkg;
    for(i$ = 0; i$ < len$; ++i$) {
        pkg = arr$[i$];
        if(StringUtils.hasText(pkg)) {
            basePackages.add(pkg);
        }
    }

    arr$ = annoAttrs.getStringArray("basePackages");
    len$ = arr$.length;

    for(i$ = 0; i$ < len$; ++i$) {
        pkg = arr$[i$];
        if(StringUtils.hasText(pkg)) {
            basePackages.add(pkg);
        }
    }

    Class[] arr$ = annoAttrs.getClassArray("basePackageClasses");
    len$ = arr$.length;

    for(i$ = 0; i$ < len$; ++i$) {
        Class<?> clazz = arr$[i$];
        basePackages.add(ClassUtils.getPackageName(clazz));
    }

    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
}

1.2 xml配置

  • scan配置扫描的相关参数,初始化ClassPathMapperScanner,调用scanner.doScan()进行包扫描

1.3 MapperScannerConfigurer

  • 初始化ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  • 调用扫描函数scanner.scan
  • ClassPathBeanDefinitionScanner.doScan()扫描包路径,获取接口类的Set<BeanDefinitionHolder>
  • ClassPathMapperScanner.doScan()把扫描到的接口类BeanDefinitionHolder修改为mybatis中使用的MapperFactoryBean.class的BeanDefinitionHolder

1.4 ClassPathMapperScanner

  • 设置类型definition.setBeanClass(MapperFactoryBean.class);
  • 设置PropertyValues,用于注入mapperInterface接口类参数
    definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
  • addToConfig属性注入,接口表示需要添加到mybatis配置管理中
  • 有sqlsession工厂配置,则设置PropertyValues注入;无工厂属性则设置为自动按类型注入。
  • 返回接口对应的beandefinition

1.5 MapperFactoryBean

  • 初始化时,通过 InitializingBean接口方法afterPropertiesSet把dao接口添加到mybatis的配置中,格式是Map<接口,MapperProxyFactory>
  • 这是一个工厂bean,用户从spring获取到的对应dao接口的bean对象,实际获取到的是接口的MapperProxyFactory。
public T getObject() throws Exception {
    return this.getSqlSession().getMapper(this.mapperInterface);
}
  • MapperProxyFactory是一个代理工厂,创建MapperProxy,代理dao接口的实际sql实现。即mybatis从sql.xml中解析出的sql语句

二 事务管理

2.1 事务管理工厂类

  • SpringManagedTransactionFactory

2.2 事务管理类

  • SpringManagedTransaction
  • autoCommit纪录是否自动提交
  • isConnectionTransactional纪录是否事务性数据库连接

2.2.1 获取sqlconnection接口

this.connection = DataSourceUtils.getConnection(this.dataSource);

  • Connection con = dataSource.getConnection();从数据库连接池获取数据库连接,非事务直接返回。事务则封装到ConnectionHolder中。
  • TransactionSynchronizationManager使用线程变量ThreadLocal<Map<Object, ConnectionHolder>> resources存储事务型数据库连接。
    @Transactional注解的spring事务代理入口,调用DataSourceTransactionManager接口在TransactionSynchronizationManager存储线程共用的事务ConnectionHolder。
  • TransactionSynchronizationManager使用线程变量ThreadLocal<Set<TransactionSynchronization>> synchronizations表示是否处于spring事务管理中

2.3 事务关系图

事务关系图.png

三 sqlSession

3.1 SqlSessionTemplate

3.1.1 使用场景

  • MapperFactoryBean父类SqlSessionDaoSupport自动注入SqlSessionFactory。实际注入SqlSessionTemplate(sqlSessionFactory)
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if(!this.externalSqlSession) {
        this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }

}

3.1.2 内部属性

  • PersistenceExceptionTranslator异常转换器,转换mybatis的PersistenceException异常为spring的DataAccessException异常
  • ExecutorType表示sql执行时创建的执行器类型
  • SqlSessionFactory工厂类创建sql执行器DefaultSqlSession
  • SqlSession sqlSessionProxy;代理工厂类创建的DefaultSqlSession

3.1.3 代理处理函数SqlSessionInterceptor

  • 获取线程变量SqlSessionHolder,事务型则线程内共用。
    SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory)
  • 事务调用,则保存SqlSessionHolder到TransactionSynchronizationManager的线程变量中,以sessionFactory为key,用于线程内共享。
  • Object result = method.invoke(sqlSession, args); sql函数调用
  • spring管理的事务,则由spring提交,否则mybatis提交。
if(!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
    sqlSession.commit(true);
}

3.2 SqlSessionFactoryBean

  • InitializingBean.afterPropertiesSet()创建sqlSessionFactory
  • xml配置文件解析xmlConfigBuilder.getConfiguration()
  • xml映射器文件解析xmlMapperBuilder.parse()
  • 别名配置,类型处理器配置,插件配置

相关文章

网友评论

      本文标题:mybatis源码1-spring管理

      本文链接:https://www.haomeiwen.com/subject/pgdvdqtx.html