美文网首页
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