• tk Mapper原理分析


    引言

      Mybatis支持@SelectProvider注解,tk Mapper正是运用了该技术,通过解析持久类,拼接xml形式的SQL语句,重新为MappedStatment设置SqlSource实现功能。

    核心配置

    <bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
          <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
          <property name="basePackage" value="com.wjz.mapper" />
    </bean>

      private MapperHelper mapperHelper = new MapperHelper();

      @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
         // 调用mybatis的后置注册处理,扫描mapper类注册为MapperFactoryBean对象
    super.postProcessBeanDefinitionRegistry(registry); // 如果没有注册过接口,就注册默认的Mapper接口,后文详解#1 this.mapperHelper.ifEmptyRegisterDefaultInterface(); String[] names = registry.getBeanDefinitionNames(); GenericBeanDefinition definition; for (String name : names) { BeanDefinition beanDefinition = registry.getBeanDefinition(name); if (beanDefinition instanceof GenericBeanDefinition) { definition = (GenericBeanDefinition) beanDefinition;
              // 判断注册的bean是MapperFactoryBean,设置beanClass为 tk.mybatis.spring.mapper.MapperFactoryBean
              // 设置MapperHelper属性
    if (StringUtil.isNotEmpty(definition.getBeanClassName()) && definition.getBeanClassName().equals("org.mybatis.spring.mapper.MapperFactoryBean")) { definition.setBeanClass(MapperFactoryBean.class); definition.getPropertyValues().add("mapperHelper", this.mapperHelper); } } } }

    书接前文#1

    MapperHelper中注册Mapper接口

    // 如果当前注册的接口为空,自动注册默认的接口tk.mybatis.mapper.common.Mapper
    public
    void ifEmptyRegisterDefaultInterface() { if (registerClass.size() == 0) { registerMapper("tk.mybatis.mapper.common.Mapper"); } }
    public void registerMapper(String mapperClass) {
            try {
                 // 实例化Mapper接口
            registerMapper(Class.forName(mapperClass)); }
    catch (ClassNotFoundException e) { throw new MapperException("注册通用Mapper[" + mapperClass + "]失败,找不到该通用Mapper!"); } }
    public void registerMapper(Class<?> mapperClass) {
            if (!registerMapper.containsKey(mapperClass)) {
                registerClass.add(mapperClass);
            // 注册Mapper的Class和通过通用Mapper接口获取对应的MapperTemplate,后文详解#2 registerMapper.put(mapperClass, fromMapperClass(mapperClass)); }
    // 自动注册继承的接口 Class<?>[] interfaces = mapperClass.getInterfaces(); if (interfaces != null && interfaces.length > 0) { for (Class<?> anInterface : interfaces) {
              // 递归注册Mapper接口继承的其他接口如BaseMapper接口 registerMapper(anInterface); } } }

    书接前文#2

    private MapperTemplate fromMapperClass(Class<?> mapperClass) {
         // 获得接口中的方法,BaseMapper接口中没有方法,SelectOneMapper接口中有selectOne方法 Method[] methods
    = mapperClass.getDeclaredMethods(); Class<?> templateClass = null; Class<?> tempClass = null; Set<String> methodSet = new HashSet<String>(); for (Method method : methods) {
            // 判断接口的方法中是否有SelectProvider注解修饰
    if (method.isAnnotationPresent(SelectProvider.class)) { SelectProvider provider = method.getAnnotation(SelectProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } else if (method.isAnnotationPresent(InsertProvider.class)) { InsertProvider provider = method.getAnnotation(InsertProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } else if (method.isAnnotationPresent(DeleteProvider.class)) { DeleteProvider provider = method.getAnnotation(DeleteProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } else if (method.isAnnotationPresent(UpdateProvider.class)) { UpdateProvider provider = method.getAnnotation(UpdateProvider.class); tempClass = provider.type(); methodSet.add(method.getName()); } if (templateClass == null) {
              // 将注解中的type属性值赋值给templateClass变量,如BaseSelectProvider templateClass
    = tempClass; } else if (templateClass != tempClass) { throw new MapperException("一个通用Mapper中只允许存在一个MapperTemplate子类!"); } }
         // 判断templateClass变量是否为null或者判断templateClass变量值是否继承自MapperTemplate如BaseSelectProvider
    if (templateClass == null || !MapperTemplate.class.isAssignableFrom(templateClass)) { templateClass = EmptyProvider.class; } MapperTemplate mapperTemplate = null; try {
            // 通过构造反射实例化MapperTemplate如BaseSelectProvider,构造参数为Mapper的Class(如SelectOneMapper.class)、MapperHelper.class mapperTemplate
    = (MapperTemplate) templateClass.getConstructor(Class.class, MapperHelper.class).newInstance(mapperClass, this); } catch (Exception e) { throw new MapperException("实例化MapperTemplate对象失败:" + e.getMessage()); } // 注册方法 for (String methodName : methodSet) { try {
              // 注册templateClass中的方法如BaseSelectProvider中的selectOne方法 mapperTemplate.addMethodMap(methodName, templateClass.getMethod(methodName, MappedStatement.
    class)); } catch (NoSuchMethodException e) { throw new MapperException(templateClass.getCanonicalName() + "中缺少" + methodName + "方法!"); } }
         // 返回Mapper模板对象
    return mapperTemplate; }

    tk.mybatis.spring.mapper.MapperScannerConfigurer后置处理时,注册了tk.mybatis.spring.mapper.MapperFactoryBean

    @Override
        protected void checkDaoConfig() {
         // 调用父类org.mybatis.spring.mapper.MapperFactoryBean,解析Mapper的注解,为Configuration注册Mapper
        
     // 如解析类注解注册Cache,解析方法注解注册MappedStatment(包括parameterType,SqlSource,ResultMap等)
    super.checkDaoConfig(); // 判断Mapper接口是否继承了通用Mapper,getObjectType()为当前Mapper接口 if (mapperHelper.isExtendCommonMapper(getObjectType())) {
            // 处理Configuration,为MappedStatment重新设置SqlSource mapperHelper.processConfiguration(getSqlSession().getConfiguration(), getObjectType()); } }
    public void processConfiguration(Configuration configuration, Class<?> mapperInterface) {
            String prefix;
            if (mapperInterface != null) {
                prefix = mapperInterface.getCanonicalName();
            } else {
                prefix = "";
            }
         // 遍历所有的MappedStatment
    for (Object object : new ArrayList<Object>(configuration.getMappedStatements())) { if (object instanceof MappedStatement) { MappedStatement ms = (MappedStatement) object; if (ms.getId().startsWith(prefix) && isMapperMethod(ms.getId())) {
                // 判断是否解析注解生成的SqlSource
    if (ms.getSqlSource() instanceof ProviderSqlSource) {
                   // 重新为MappedStatment设置SqlSource setSqlSource(ms); } } } } }
    public void setSqlSource(MappedStatement ms) {
         // 从缓存中获得MapperTemplate,如BaseSelectProvider MapperTemplate mapperTemplate
    = msIdCache.get(ms.getId()); try { if (mapperTemplate != null) { mapperTemplate.setSqlSource(ms); } } catch (Exception e) { throw new RuntimeException(e); } }
    public void setSqlSource(MappedStatement ms) throws Exception {
            if (this.mapperClass == getMapperClass(ms.getId())) {
                throw new RuntimeException("请不要配置或扫描通用Mapper接口类:" + this.mapperClass);
            }
         // 从缓存中获得方法,如selectOne方法 Method method
    = methodMap.get(getMethodName(ms)); try { //第一种,直接操作ms,不需要返回值 if (method.getReturnType() == Void.TYPE) { method.invoke(this, ms); } //第二种,返回SqlNode else if (SqlNode.class.isAssignableFrom(method.getReturnType())) { SqlNode sqlNode = (SqlNode) method.invoke(this, ms); DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode); setSqlSource(ms, dynamicSqlSource); } //第三种,返回xml形式的sql字符串 else if (String.class.equals(method.getReturnType())) {
              // 方法反射调用,如selectOne方法,后文详解#3 String xmlSql
    = (String) method.invoke(this, ms);
              // 通过LanguageDriver创建SqlSource SqlSource sqlSource
    = createSqlSource(ms, xmlSql); // 替换原有的SqlSource,后文详解#4 setSqlSource(ms, sqlSource); } else { throw new RuntimeException("自定义Mapper方法返回类型错误,可选的返回类型为void,SqlNode,String三种!"); } //cache checkCache(ms); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getTargetException() != null ? e.getTargetException() : e); } }

    书接前文#3

    以BaseSelectProvider的selectOne方法为例

    public String selectOne(MappedStatement ms) {
         // 从MappedStatment中拿到MapperClass,如com.wjz.StudentMapper.class
         // 再拿到StudentMapper的泛型类型,如Student.class,后文详解#3-1
    Class
    <?> entityClass = getEntityClass(ms); // 修改返回值类型为实体类型,后文详解#3-2 setResultType(ms, entityClass); StringBuilder sql = new StringBuilder();
         // 拼接查询的字段,后文详解#3-3 sql.append(SqlHelper.selectAllColumns(entityClass));
         // 拼接表名,表名从EntityTable中的name属性中拿 sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
         // 拼接where条件,后文详解#3-4 sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
    return sql.toString(); }

    书接前文#3-1

    public Class<?> getEntityClass(MappedStatement ms) {
            String msId = ms.getId();
            if (entityClassMap.containsKey(msId)) {
           // 从缓存中获得
    return entityClassMap.get(msId); } else { Class<?> mapperClass = getMapperClass(msId); Type[] types = mapperClass.getGenericInterfaces(); for (Type type : types) { if (type instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) type; if (t.getRawType() == this.mapperClass || this.mapperClass.isAssignableFrom((Class<?>) t.getRawType())) { Class<?> returnType = (Class<?>) t.getActualTypeArguments()[0]; // 获取该类型后,第一次对该类型进行初始化 EntityHelper.initEntityNameMap(returnType, mapperHelper.getConfig());
                   // 放置到缓存中 entityClassMap.put(msId, returnType);
    return returnType; } } } } throw new RuntimeException("无法获取Mapper<T>泛型类型:" + msId); }
    public static synchronized void initEntityNameMap(Class<?> entityClass, Config config) {
            if (entityTableMap.get(entityClass) != null) {
                return;
            }
            Style style = config.getStyle();
            // 检查类上是否有NameStyle注解,有的话获得Style枚举的值
            if (entityClass.isAnnotationPresent(NameStyle.class)) {
                NameStyle nameStyle = entityClass.getAnnotation(NameStyle.class);
                style = nameStyle.value();
            }
    
            // 创建并缓存EntityTable
            EntityTable entityTable = null;
            if (entityClass.isAnnotationPresent(Table.class)) {
                Table table = entityClass.getAnnotation(Table.class);
                if (!table.name().equals("")) {
                    entityTable = new EntityTable(entityClass);
                    entityTable.setTable(table);
                }
            }
            if (entityTable == null) {
                entityTable = new EntityTable(entityClass);
                // 可以通过style控制
                entityTable.setName(StringUtil.convertByStyle(entityClass.getSimpleName(), style));
            }
            entityTable.setEntityClassColumns(new LinkedHashSet<EntityColumn>());
            entityTable.setEntityClassPKColumns(new LinkedHashSet<EntityColumn>());
            // 处理所有列
            List<EntityField> fields = null;
            if (config.isEnableMethodAnnotation()) {
                fields = FieldHelper.getAll(entityClass);
            } else {
                fields = FieldHelper.getFields(entityClass);
            }
            for (EntityField field : fields) {
           // 加工字段,后文详解 processField(entityTable, style, field); }
    // 当pk.size=0的时候使用所有列作为主键 if (entityTable.getEntityClassPKColumns().size() == 0) { entityTable.setEntityClassPKColumns(entityTable.getEntityClassColumns()); } entityTable.initPropertyMap(); entityTableMap.put(entityClass, entityTable); }

    加工字段

    private static void processField(EntityTable entityTable, Style style, EntityField field) {
            // 如果持久类中有字段被Transient注解修饰排除该字段
            if (field.isAnnotationPresent(Transient.class)) {
                return;
            }
            // Id注解
            EntityColumn entityColumn = new EntityColumn(entityTable);
            if (field.isAnnotationPresent(Id.class)) {
                entityColumn.setId(true);
            }
            // Column注解
            String columnName = null;
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                columnName = column.name();
                entityColumn.setUpdatable(column.updatable());
                entityColumn.setInsertable(column.insertable());
            }
            // ColumnType注解
            if (field.isAnnotationPresent(ColumnType.class)) {
                ColumnType columnType = field.getAnnotation(ColumnType.class);
                // column可以起到别名的作用
                if (StringUtil.isEmpty(columnName) && StringUtil.isNotEmpty(columnType.column())) {
                    columnName = columnType.column();
                }
                if (columnType.jdbcType() != JdbcType.UNDEFINED) {
                    entityColumn.setJdbcType(columnType.jdbcType());
                }
                if (columnType.typeHandler() != UnknownTypeHandler.class) {
                    entityColumn.setTypeHandler(columnType.typeHandler());
                }
            }
            // 当字段没有被Column注解修饰时,通过Style枚举值获得字段名,后文详解
            if (StringUtil.isEmpty(columnName)) {
                columnName = StringUtil.convertByStyle(field.getName(), style);
            }
            entityColumn.setProperty(field.getName());
            entityColumn.setColumn(columnName);
            entityColumn.setJavaType(field.getJavaType());
            // OrderBy注解
            if (field.isAnnotationPresent(OrderBy.class)) {
                OrderBy orderBy = field.getAnnotation(OrderBy.class);
                if (orderBy.value().equals("")) {
                    entityColumn.setOrderBy("ASC");
                } else {
                    entityColumn.setOrderBy(orderBy.value());
                }
            }
            // 主键策略 - Oracle序列,MySql自动增长,UUID
            if (field.isAnnotationPresent(SequenceGenerator.class)) {
                SequenceGenerator sequenceGenerator = field.getAnnotation(SequenceGenerator.class);
                if (sequenceGenerator.sequenceName().equals("")) {
                    throw new RuntimeException(entityTable.getEntityClass() + "字段" + field.getName() + "的注解@SequenceGenerator未指定sequenceName!");
                }
                entityColumn.setSequenceName(sequenceGenerator.sequenceName());
            } else if (field.isAnnotationPresent(GeneratedValue.class)) {
                GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
                if (generatedValue.generator().equals("UUID")) {
                    entityColumn.setUuid(true);
                } else if (generatedValue.generator().equals("JDBC")) {
                    entityColumn.setIdentity(true);
                    entityColumn.setGenerator("JDBC");
                    entityTable.setKeyProperties(entityColumn.getProperty());
                    entityTable.setKeyColumns(entityColumn.getColumn());
                } else {
                    //允许通过generator来设置获取id的sql,例如mysql=CALL IDENTITY(),hsqldb=SELECT SCOPE_IDENTITY()
                    //允许通过拦截器参数设置公共的generator
                    if (generatedValue.strategy() == GenerationType.IDENTITY) {
                        //mysql的自动增长
                        entityColumn.setIdentity(true);
                        if (!generatedValue.generator().equals("")) {
                            String generator = null;
                            IdentityDialect identityDialect = IdentityDialect.getDatabaseDialect(generatedValue.generator());
                            if (identityDialect != null) {
                                generator = identityDialect.getIdentityRetrievalStatement();
                            } else {
                                generator = generatedValue.generator();
                            }
                            entityColumn.setGenerator(generator);
                        }
                    } else {
                        throw new RuntimeException(field.getName()
                                + " - 该字段@GeneratedValue配置只允许以下几种形式:" +
                                "
    1.全部数据库通用的@GeneratedValue(generator="UUID")" +
                                "
    2.useGeneratedKeys的@GeneratedValue(generator=\"JDBC\")  " +
                                "
    3.类似mysql数据库的@GeneratedValue(strategy=GenerationType.IDENTITY[,generator="Mysql"])");
                    }
                }
            }
            entityTable.getEntityClassColumns().add(entityColumn);
            if (entityColumn.isId()) {
                entityTable.getEntityClassPKColumns().add(entityColumn);
            }
        }

    通过Style枚举值获得字段名

    public static String convertByStyle(String str, Style style) {
            switch (style) {
           // 去掉下划线
    case camelhump: return camelhumpToUnderline(str);
           // 改成大写
    case uppercase: return str.toUpperCase();
           // 改成小写
    case lowercase: return str.toLowerCase();
           // 去掉下划线并改成小写
    case camelhumpAndLowercase: return camelhumpToUnderline(str).toLowerCase();
           // 去掉下划线并改成大写
    case camelhumpAndUppercase: return camelhumpToUnderline(str).toUpperCase();
           // 什么都不做
    case normal: default: return str; } }

    书接前文#3-2

    protected void setResultType(MappedStatement ms, Class<?> entityClass) {
         // 从缓存中拿到EntityTable EntityTable entityTable
    = EntityHelper.getEntityTable(entityClass); List<ResultMap> resultMaps = new ArrayList<ResultMap>();
         // 从缓存中拿到ResultMap添加到List中 resultMaps.add(entityTable.getResultMap(ms.getConfiguration())); MetaObject metaObject
    = SystemMetaObject.forObject(ms);
         // 通过反射为Configuration设置resultMaps属性设置值 metaObject.setValue(
    "resultMaps", Collections.unmodifiableList(resultMaps)); }

    书接前文#3-3

    public static String selectAllColumns(Class<?> entityClass) {
            StringBuilder sql = new StringBuilder();
            sql.append("SELECT ");
         // 拼接所有的查询字段 sql.append(getAllColumns(entityClass)); sql.append(
    " "); return sql.toString(); }
    public static String getAllColumns(Class<?> entityClass) {
         // 使用EntityHelper根据实例Class获得所有EntityColumn,EntityTable中有Set<EntityColumn>属性 Set
    <EntityColumn> columnList = EntityHelper.getColumns(entityClass); StringBuilder sql = new StringBuilder();
         // 循环所有的EntityColumn,拼接字段
    for (EntityColumn entityColumn : columnList) { sql.append(entityColumn.getColumn()).append(","); } return sql.substring(0, sql.length() - 1); }

    书接前文#3-4

    public static String whereAllIfColumns(Class<?> entityClass, boolean empty) {
            StringBuilder sql = new StringBuilder();
         // 拼接XML形式的XNode sql.append(
    "<where>"); //获取全部列 Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass); //当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值 for (EntityColumn column : columnList) { sql.append(getIfNotNull(column, " AND " + column.getColumnEqualsHolder(), empty)); } sql.append("</where>"); return sql.toString(); }

    书接前文#4

    protected void setSqlSource(MappedStatement ms, SqlSource sqlSource) {
         // 通过反射为MappedStatment设置SqlSource MetaObject msObject
    = SystemMetaObject.forObject(ms); msObject.setValue("sqlSource", sqlSource); //如果是Jdbc3KeyGenerator,就设置为MultipleJdbc3KeyGenerator KeyGenerator keyGenerator = ms.getKeyGenerator(); if (keyGenerator instanceof Jdbc3KeyGenerator) { msObject.setValue("keyGenerator", new MultipleJdbc3KeyGenerator()); } }
  • 相关阅读:
    也谈用反射实现Enum→String映射:一种重视性能的方法【转载】
    C#对象的浅拷贝,深拷贝【转载】
    int转byte[],byte[]转int
    TF31003:您的用户帐户没有连接到 Team Foundation Server 的权限
    关于枚举的双语显示问题
    浅析C#深拷贝与浅拷贝
    反射枚举变量
    C#路径/文件/目录/I/O常见操作汇总(二)
    【转】正确理解ThreadLocal
    【转】JSP的九个隐含对象
  • 原文地址:https://www.cnblogs.com/BINGJJFLY/p/7902563.html
Copyright © 2020-2023  润新知