• TSharding源码阅读


    需要的背景知识:Spring 和Mybatis 实现原理和源码, javaassist字节码增强的使用, java及设计模式的使用  

    1 读取解析数据库配置文件

    DataSourceScanner实现了Spring的BeanDefinitionRegistryPostProcessor和ApplicationContextAware接口。

    BeanDefinitionRegistryPostProcessor 允许定义bean

    ApplicationContextAware 可以获取Spring上下文。

    代码流程:getDataSources解析读取数据库配置文件生成dataSourcesMapping( Map<String, Map<DataSourceType, DataSource>>),registerDataSources 遍历dataSourcesMapping生成DataSourceFactoryBean(名字格式trade0005SlaveDataSource)并注入到SpringBean工厂。继续遍历解析数据源,封装成Map<String, ReadWriteSplittingDataSource> ,如果有可写数据源则创建事务管理器(名字格式trade0005TransactionManager),注册到SpringBean工厂。如果可写数据源不存在,注册一个空transactionManager。如果只有一个可写数据源,则添加别名,兼容默认情况。解析完数据源后,向Spring注册dataSourceLookup,其实就是把数据源map保存起来。

    2 MapperScannerWithSharding 

      Tsharding MybatisMapper的扫描类,负责将Mapper接口与对应的xml配置文件整合,绑定设定的数据源,注入到Spring Context中。

      实现了BeanFactoryPostProcessor, InitializingBean 接口  。BeanFactoryPostProcessor可以修改BEAN的配置信息

      代码流程:

          获取1步中注册的dataSourceLookup。

        initSqlSessionFactories。第一次SqlSessionFactoryBean.setMapperLocations.setDataSource.setTypeAliasesPackage(mapper位置,数据源,实体类),实例化SqlSessionFactoryBean,单例注册到bean工厂(名字格式为trade0001)。后续,从第一次的sessionFactoryBean.getObject()获取一个SqlSessionFactory,

    然后从SqlSessionFactory获取configuration,就是Resource,

    从Resource获取SqlSessionFactory返回Configuration,从Configuration获取mappedStatements( Map<String, MappedStatement>),

    然后为了后续的元数据复用再 Map<String, MappedStatement> 放回Configuration.最后使用SqlSessionFactoryLookup 把所有sqlSessionFactories保存起来,放入MapperScannerWithSharding

      ClassPathScanHandler:扫描所有配置文件下所以java类,

         新生成mapper,如果这些类是mapper类,新生成,并单例注册到bean工厂

      

        private Object newMapper(final Class<?> clazz) {
    
            final Invoker invoker = new TShardingRoutingInvokeFactory(sqlSessionFactoryLookup).newInvoker(clazz);
      //动态代理 invoker
            return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz},
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
                            return invoker.invoke(new DefaultInvocation(method, args));
                        }
                    });
        }
    

      

    TShardingRoutingInvokeFactory 类:
     判断mapperInterface 是否带注解,如果注解为TShardingRoutingHandler,使用Sharding数据源,走分表分库。
    不带注解,正常的使用配置的数据源。 走分表分库分支:返回内部类Invoker


    3:MapperShardingInitializer 增强Mapper处理总入口:Mapper被mybatis初始化后,在这里做进一步的处理和增强、

      http://www.cnblogs.com/clds/p/5966815.html

        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            Map<String, SqlSessionFactory> sqlSessionFactories = applicationContext.getBeansOfType(SqlSessionFactory.class);
            if (sqlSessionFactories.isEmpty()) {
                return;
            }
            MapperHelperForSharding mapperHelperForSharding = new MapperHelperForSharding();
            List<SqlSession> sqlSessions = new ArrayList<>(sqlSessionFactories.size());
            for (SqlSessionFactory sqlSessionFactory : sqlSessionFactories.values()) {
                SqlSession sqlSession = new SqlSessionTemplate(sqlSessionFactory);
                sqlSessions.add(sqlSession);
            }
            //Mapper代码增强 每个方法扩展出一个ShardingMapper类,增强为512个方法。
            this.needEnhancedClassesArray = needEnhancedClasses.split(",");
            this.enhanceMapperClass();
            mapperHelperForSharding.setMappers(needEnhancedClassesArray);
            mapperHelperForSharding.setSqlSessions(sqlSessions.toArray(new SqlSession[0]));
            mapperHelperForSharding.initMapper();
        }

    4:执行dao方法
      因为是动态代理,又返回到TShardingRoutingInvokeFactory。

      使用动态代理的原因:Object mapper = this.newMapper(clazz);

        beanFactory.registerSingleton(Character.toLowerCase(clazz.getSimpleName().charAt(0))+ clazz.getSimpleName().substring(1), mapper);
      bean工厂中只注入了shopOrderMapper ,但是实际执行的时候需要找到增强后的方法

    new Invoker() {
                    @Override
                    public Object invoke(Invocation invocation) throws Throwable {
    
                        Method method = invocation.getMethod();
                        ShardingMetadata shardingMetadata = getShardingKey(method, invocation.getArgs());//根据分片参数获取schemaName+tableSuffix
    
                        if (shardingMetadata == null) {
                            throw new DataSourceRoutingException("dataSourceRouting error! Method Name:" + method.getName() + " shardingMetadata is null!");
                        }
    
                        //走分库分表环境
                        logger.debug("TShardingRoutingInvokeFactory routing to sharding db. Method Name:" + method.getName() + ". ShardingKey:" + shardingMetadata.getShardingKey());
    
                        Class newClass = clazz;
                        if (!"".equals(shardingMetadata.getSchemaName())) {
                            newClass = Class.forName(clazz.getCanonicalName() + "Sharding" + method.getName());//找到对应增强后的class
                        }
                ////newMethod:getShopOrderByShopOrderIds0064 Method newMethod
    = newClass.getMethod(method.getName() + shardingMetadata.getTableSuffix(), method.getParameterTypes()); MapperBasicConfig config = new MapperBasicConfig(newClass, shardingMetadata.getSchemaName());//应该走哪个数据源 final Object mapper = newMyBatisMapper(config);//获取到对应的mapper ShopOrderMapperShardinggetShopOrderByShopOrderIds try { ReadWriteSplittingContextInitializer.initReadWriteSplittingContext(invocation.getMethod());//框架会回调此方法,判断数据源类型,获取数据源类型 master or slave return newMethod.invoke(mapper, invocation.getArgs());//执行dao方法 } finally { ReadWriteSplittingContextInitializer.clearReadWriteSplittingContext(); } } }
  • 相关阅读:
    [RxJS] ReplaySubject
    [React Fundamentals] Composable Components
    [Webpack] Use the Webpack Dashboard to Monitor Webpack Operations
    [RxJS] AsyncSubject
    [React Fundamentals] Component Lifecycle
    [React Fundamentals] Component Lifecycle
    [React Fundamentals] Component Lifecycle
    [RxJS] Subject basic
    [React Fundamentals] Using Refs to Access Components
    文档管理系统二——文档扫描与图片编辑
  • 原文地址:https://www.cnblogs.com/clds/p/5963079.html
Copyright © 2020-2023  润新知