引言
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配置只允许以下几种形式:" + "\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()); } }