文档章节

TSharding源码阅读-MapperShardingInitializer

穿林度水
 穿林度水
发布于 2016/11/07 14:27
字数 1051
阅读 6
收藏 0
/**
 * 增强Mapper处理总入口:Mapper被mybatis初始化后,在这里做进一步的处理和增强
 *
 * @author qigong on 5/1/15
 */
public class MapperShardingInitializer implements ApplicationContextAware {


    Logger logger = LoggerFactory.getLogger(getClass());

    private String needEnhancedClasses;
    private String[] needEnhancedClassesArray;

    @Override
    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();
    }

    private void enhanceMapperClass() {
        for (String mapperClass : needEnhancedClassesArray) {
            try {
                MapperEnhancer.enhanceMapperClass(mapperClass);
            } catch (Exception e) {
                logger.error("Enhance {} class error", mapperClass, e);
            }
        }
    }

    public void setNeedEnhancedClasses(String needEnhancedClasses) {
        this.needEnhancedClasses = needEnhancedClasses;
    }
}

 

 

3.1 this.enhanceMapperClass();

  

/**
     * 对mapper进行增强,生成新的mapper,并主动加载新mapper类到classloader
     *
     * @param mapperClassName
     */
    public static void enhanceMapperClass(String mapperClassName) throws Exception {
        //com.mogujie.service.tsharding.mapper.ShopOrderMapper
        Class originClass = Class.forName(mapperClassName);//获取A
        Method[] originMethods = originClass.getDeclaredMethods();//获取A的方法,

        CtClass cc = pool.get(mapperClassName);//获取到class定义的容器ClassPool,通过它获取已经编译好的类A

        for (CtMethod ctMethod : cc.getDeclaredMethods()) {//遍历A的所有方法
            CtClass enhanceClass = pool.makeInterface(mapperClassName + "Sharding" + ctMethod.getName());//针对A的每一个方法新建一个接口B
            //com.mogujie.service.tsharding.mapper.ShopOrderMapperShardinggetShopOrderByShopOrderId
            for (long i = 0L; i < 512; i++) {//生成512个方法
                CtMethod newMethod = new CtMethod(ctMethod.getReturnType(), ctMethod.getName() + ShardingCaculator.getNumberWithZeroSuffix(i), ctMethod.getParameterTypes(), enhanceClass);
                //CtMethod 和CtConstructor 提供了 insertBefore()、insertAfter()和 addCatch()方法,它们可以插入一个souce文本到存在的方法的相应的位置
                Method method = getOriginMethod(newMethod, originMethods);//获取A的方法
                if(method.getParameterAnnotations()[0].length > 0) {//如果带注解
                    ClassFile ccFile = enhanceClass.getClassFile();
                    ConstPool constPool = ccFile.getConstPool();

                    //拷贝注解信息和注解内容,以支持mybatis mapper类的动态绑定
                    newMethod.getMethodInfo().addAttribute(MapperAnnotationEnhancer.duplicateParameterAnnotationsAttribute(constPool, method));
                }
                enhanceClass.addMethod(newMethod);//B增加方法
            }
            Class<?> loadThisClass = enhanceClass.toClass();

            //2015.09.22后不再输出类到本地
            enhanceClass.writeFile(".");
        }
    }

  需要增强的类

@DataSourceRouting(handler=TShardingRoutingHandler.class)
public abstract interface ShopOrderMapper
{
  @ShardingExtensionMethod(type=MapperResourceEnhancer.class, method="enhancedShardingSQL")
  public abstract ShopOrder getShopOrderByShopOrderId(@ShardingOrderPara Long paramLong);

  @ShardingExtensionMethod(type=MapperResourceEnhancer.class, method="enhancedShardingSQL")
  public abstract List<ShopOrder> getShopOrderByShopOrderIds(@ShardingOrderPara List<Long> paramList);

  @ShardingExtensionMethod(type=MapperResourceEnhancer.class, method="enhancedShardingSQL")
  public abstract int batchUpdateShopOrderByShopOrderIds(@ShardingOrderPara @Param("shopOrderIds") List<Long> paramList, @Param("shopOrder") ShopOrder paramShopOrder);
}

增强后针对每一个方法都生成了一个类

public abstract interface ShopOrderMapperShardingbatchUpdateShopOrderByShopOrderIds
{
  public abstract int batchUpdateShopOrderByShopOrderIds0000(@ShardingOrderPara("orderId") @Param("shopOrderIds") List paramList, @Param("shopOrder") ShopOrder paramShopOrder);

  public abstract int batchUpdateShopOrderByShopOrderIds0001(@ShardingOrderPara("orderId") @Param("shopOrderIds") List paramList, @Param("shopOrder") ShopOrder paramShopOrder);

  public abstract int batchUpdateShopOrderByShopOrderIds0002(@ShardingOrderPara("orderId") @Param("shopOrderIds") List paramList, @Param("shopOrder") ShopOrder paramShopOrder);

  public abstract int batchUpdateShopOrderByShopOrderIds0003(@ShardingOrderPara("orderId") @Param("shopOrderIds") List paramList, @Param("shopOrder") ShopOrder paramShopOrder);

  public abstract int batchUpdateShopOrderByShopOrderIds0004(@ShardingOrderPara("orderId") @Param("shopOrderIds") List paramList, @Param("shopOrder") ShopOrder paramShopOrder);
public abstract interface ShopOrderMapperShardinggetShopOrderByShopOrderId
{
  public abstract ShopOrder getShopOrderByShopOrderId0000(@ShardingOrderPara("orderId") Long paramLong);

  public abstract ShopOrder getShopOrderByShopOrderId0001(@ShardingOrderPara("orderId") Long paramLong);

  public abstract ShopOrder getShopOrderByShopOrderId0002(@ShardingOrderPara("orderId") Long paramLong);

  public abstract ShopOrder getShopOrderByShopOrderId0003(@ShardingOrderPara("orderId") Long paramLong);

  public abstract ShopOrder getShopOrderByShopOrderId0004(@ShardingOrderPara("orderId") Long paramLong);

  public abstract ShopOrder getShopOrderByShopOrderId0005(@ShardingOrderPara("orderId") Long paramLong);

  public abstract ShopOrder getShopOrderByShopOrderId0006(@ShardingOrderPara("orderId") Long paramLong);

  public abstract ShopOrder getShopOrderByShopOrderId0007(@ShardingOrderPara("orderId") Long paramLong);
}
public abstract interface ShopOrderMapperShardinggetShopOrderByShopOrderIds
{
  public abstract List getShopOrderByShopOrderIds0000(@ShardingOrderPara("orderId") List paramList);

  public abstract List getShopOrderByShopOrderIds0001(@ShardingOrderPara("orderId") List paramList);

  public abstract List getShopOrderByShopOrderIds0002(@ShardingOrderPara("orderId") List paramList);

  public abstract List getShopOrderByShopOrderIds0003(@ShardingOrderPara("orderId") List paramList);

  public abstract List getShopOrderByShopOrderIds0004(@ShardingOrderPara("orderId") List paramList);

  public abstract List getShopOrderByShopOrderIds0005(@ShardingOrderPara("orderId") List paramList);

  public abstract List getShopOrderByShopOrderIds0006(@ShardingOrderPara("orderId") List paramList);

  public abstract List getShopOrderByShopOrderIds0007(@ShardingOrderPara("orderId") List paramList);
}

 

3.2 mapperHelperForSharding.setMappers(needEnhancedClassesArray);
  通过ShopOrderMapper.java,获取注解配置 @ShardingExtensionMethod(type = MapperResourceEnhancer.class, method = "enhancedShardingSQL"),
  生成MapperEnhancer,以ShopOrderMapper的方法名为key,MapperResourceEnhancer.enhancedShardingSQL 为value,保存在MapperResourceEnhancer.methodMap中。
  返回MapperEnhancer,再以ShopOrderMappe 为key,MapperEnhancer为value,保存在MapperHelperForSharding.registerMapper中,供后续使用
3.3 mapperHelperForSharding.setSqlSessions(sqlSessions.toArray(new SqlSession[0]));
  把sqlSession保存在mapperHelperForSharding.sqlSessions
3.4 mapperHelperForSharding.initMapper();( Spring4 is necessary)
  类关系:SqlSession>Configuration>MappedStatement>DynamicSqlSource||RawSqlSource
  遍历 sqlSessions,处理Configuration中全部的MappedStatement,重新设置SqlSource。
  重新设置SqlSource:获取MapperTemplate(3.2mapperHelperForSharding.registerMapper中保存的MapperEnhancer)。
  然后 mapperEnhancer.setSqlSource(ms, configuration);代码增强 扩充为512个方法。 

  

public void setSqlSource(MappedStatement ms, Configuration configuration) throws Exception {
                    Method method = methodMap.get(getMethodName(ms));//3.2中保存的enhancedShardingSQL方法
                    try {
                        if (method.getReturnType() == Void.TYPE) {
                            method.invoke(this, ms);
                        } else if (SqlSource.class.isAssignableFrom(method.getReturnType())) {
                            //代码增强 扩充为512个方法。
                            for (long i = 0; i < 512; i++) {

                                //新的带sharding的sql
                                SqlSource sqlSource = (SqlSource) method.invoke(this, ms, configuration, i);

                                String newMsId = ms.getId() + ShardingCaculator.getNumberWithZeroSuffix(i);
                                newMsId = newMsId.replace("Mapper.", "MapperSharding" + getMethodName(ms) + ".");

                                //添加到ms库中
                                MappedStatement newMs = copyFromMappedStatement(ms, sqlSource, newMsId);
                                configuration.addMappedStatement(newMs);
                                setSqlSource(newMs, sqlSource);
                            }
                        } else {
                            throw new RuntimeException("自定义Mapper方法返回类型错误,可选的返回类型为void和SqlNode!");
                        }
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    } catch (InvocationTargetException e) {
                        throw new RuntimeException(e.getTargetException() != null ? e.getTargetException() : e);
                    }
                }

 

3.4.1 SqlSource sqlSource = (SqlSource) method.invoke(this, ms, configuration, i);
  实际调用com.mogujie.trade.tsharding.route.orm.MapperResourceEnhancer;enhancedShardingSQL
    (SqlSession>Configuration>MappedStatement>DynamicSqlSource||RawSqlSource)
     DynamicSqlSource中存在mapperxml中每个节点的语句。
       awSqlSource中存在mapperxml中的sql语句。根据分片参数替换成对应的表名,比如TradeOrder0066
    最终生成的sql语句类似(SELECT orderId, buyerUserId,sellerUserId FROM TradeOrder0066 WHERE orderId = ? limit 1)
  用新ID,创建MappedStatement(mapperxml节点),添加到Configuration,设置数据源
     新ID格式:com.mogujie.service.tsharding.mapper.ShopOrderMapperShardinggetShopOrderByShopOrderId.getShopOrderByShopOrderId0000

© 著作权归作者所有

穿林度水
粉丝 0
博文 250
码字总数 167120
作品 0
海淀
程序员
私信 提问
Mybatis 分库分表组件--TSharding-Client

TSharding 是 应用于蘑菇街交易平台的一个简易 sharding 组件,也是一个 Mybatis 分库分表组件。 TSharding 组件目标: 很少的资源投入即可开发完成 支持交易订单表的Sharding需求,分库又分...

匿名
2016/08/17
4.6K
3
撸码工匠/vue-admin-block

Vuejs Admin Block 特性 基于 Vue, iView, Axios, Mock 企业级后台管理系统最佳实践。 技术栈 Axios @0.x iView @2.x Mockjs @1.x Vue @2.5.x Vue-Router @3.x Vuex @3.x ES6 SCSS 开发构建 ......

撸码工匠
2018/01/14
0
0
令人生畏的源码,到底该怎样看?

一个软件开发人员,工作到了一定的年限(一般是3、4年左右),如果他还没学会阅读源码,那么他就会遇到瓶颈。因为到了这个时候的开发,他应该不仅仅只会做那些 CURD 的业务逻辑,而应该会根据...

技术小能手
2018/09/05
0
0
【超实用】面对枯燥的源码,如何才能坚持看下去?

一个软件开发人员,工作到了一定的年限(一般是3、4年左右),如果他还没学会阅读源码,那么他就会遇到瓶颈。因为到了这个时候的开发,他应该不仅仅只会做那些 CURD 的业务逻辑,而应该会根据...

陈树义
2018/08/28
0
0
【实用】面对枯燥的源码,如何才能看得下去?

一个软件开发人员,工作到了一定的年限(一般是3、4年左右),如果他还没学会阅读源码,那么他就会遇到瓶颈。因为到了这个时候的开发,他应该不仅仅只会做那些 CURD 的业务逻辑,而应该会根据...

技术小能手
2018/09/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
今天
1K
12
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
22
0
计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
15
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
25
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部