zoukankan      html  css  js  c++  java
  • TSharding源码阅读-MapperShardingInitializer

    
    
    /**
     * 增强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

  • 相关阅读:
    终于找到个eclipse的高级点的插件了!
    ArrayList排序 降序排列
    sql语法总结
    preparedStatement的用法总结
    ReactiveCocoa源码解读(二)
    ReactiveCocoa源码解读(一)
    ReactiveCocoa应用篇(二)
    ReactiveCocoa应用篇(一)
    iOS
    Monad详解
  • 原文地址:https://www.cnblogs.com/clds/p/5966815.html
Copyright © 2011-2022 走看看