tk.mapper_需求分析4个步骤

tk.mapper_需求分析4个步骤引言  Mybatis支持@SelectProvider注解,tkMapper正是运用了该技术,通过解析持久类,拼接xml形式的SQL语句,重新为MappedStatment设置SqlSource实现功能。核心配置<beanclass=”tk.mybatis.spring.mapper.MapperScannerConfigurer”>&l…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

引言

  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>

tk.mapper_需求分析4个步骤

  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

tk.mapper_需求分析4个步骤

@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配置只允许以下几种形式:" +
                            "\n1.全部数据库通用的@GeneratedValue(generator=\"UUID\")" +
                            "\n2.useGeneratedKeys的@GeneratedValue(generator=\\\"JDBC\\\")  " +
                            "\n3.类似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()); } }

 

转载于:https://www.cnblogs.com/BINGJJFLY/p/7902563.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/188489.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Java:StringBuilder的基本使用

    Java:StringBuilder的基本使用概述StringBuilder表面看起来是用来拼接、处理字符串的一个工具类,但它的内部实现其实是处理字符序列。StringBuilder比String具有使用更加方便、运行效率更高的特点。StringBuffer是在StringBuilder的基础上多了线程安全(同步访问)。拼接、反序、替换、删减、插入append(),用于拼接,可接受字符串以及所有的基本数据类型的数据。StringBuildersb=newStringBuilder();sb.ap

  • 设置CListCtrl单元格的颜色

    设置CListCtrl单元格的颜色pragmaonce//CListCtrlClclassCListCtrlCl:publicCListCtrl{DECLARE_DYNAMIC(CListCtrlCl)public:CListCtrlCl();virtual~CListCtrlCl();protected:DECLARE_MESSAGE_MAP()virtualvo

  • Jenkins学习一:Jenkins是什么?

    Jenkins学习一:Jenkins是什么?第一章Jenkins是什么?Jenkins是一个可扩展的持续集成引擎。主要用于:l持续、自动地构建/测试软件项目。l监控一些定时执行的任务。Jenkins拥有的特性包括:l易于安装-只要把jenkins.war部署到servlet容器,不需要数据库支持。l易于配置-所有配置都是通过其提供的web界面实现。l集成RSS/E-mail通过RSS发布构建结果…

  • 百度地图API显示多个标注点带百度样式信息检索窗口的代码

    百度地图API显示多个标注点带百度样式信息检索窗口的代码

    2021年10月10日
  • reentrantlock_lock condition

    reentrantlock_lock conditionReentrantLock锁的底层实现已经阐述过了,那么如何使用,本文进行下样例展示,主要说两个功能:1.lock及中断,2.申请等待时间;lock锁/***@Description:*@author:Erick*@version:1.0*@time:2018-9-25*/publicclassReentrantLockThreadimple…

    2022年10月11日
  • Java连接MySQL mysql-connector-java-bin.jar驱动包的下载与安装

    Java连接MySQL mysql-connector-java-bin.jar驱动包的下载与安装eclipse在连接mysql数据库的时候要通过mysql驱动包进行连接首先进入官网中—-官网地址:https://dev.mysql.com/进入官网中选择DOWNLOADS(下载)2.选择下载中的mysql-connectors3.选择connector/JJ指的是Java4.接下在选择操作系统,此处选择platformindependent(独立于平台)…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号