It's important that the type is added before the parser is run otherwise the binding may automatically be attempted by the mapper parser. If the type is already known, it won't try.
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}
public <T> void addMapper(Class<T> type) {
// 只有接口才会解析
if (type.isInterface()) {
// 重复注册的检查
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
// 记录在Map中,留意value的类型是MapperProxyFactory
knownMappers.put(type, new MapperProxyFactory<>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
// 利用MapperAnnotationBuilder解析Mapper接口
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
public class MapperAnnotationBuilder {
private final Configuration configuration;
private final MapperBuilderAssistant assistant;
private final Class<?> type;
public MapperAnnotationBuilder(Configuration configuration, Class<?> type) {
String resource = type.getName().replace('.', '/') + ".java (best guess)";
this.assistant = new MapperBuilderAssistant(configuration, resource);
this.configuration = configuration;
this.type = type;
}
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
loadXmlResource();
private void loadXmlResource() {
// Spring may not know the real resource name so we check a flag
// to prevent loading again a resource twice
// this flag is set at XMLMapperBuilder#bindMapperForNamespace
if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
// 注意上面的判断多了一个namespace的前缀
// ......
}
}
private void loadXmlResource() {
// Spring may not know the real resource name so we check a flag
// to prevent loading again a resource twice
// this flag is set at XMLMapperBuilder#bindMapperForNamespace
if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
String xmlResource = type.getName().replace('.', '/') + ".xml";
InputStream inputStream = type.getResourceAsStream("/" + xmlResource);
if (inputStream == null) {
// Search XML mapper that is not in the module but in the classpath.
try {
inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
} catch (IOException e2) {
// ignore, resource is not required
}
}
if (inputStream != null) {
XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream,
assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
xmlParser.parse();
}
}
}
private Class<?> getReturnType(Method method) {
Class<?> returnType = method.getReturnType();
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, type);
if (resolvedReturnType instanceof Class) {
returnType = (Class<?>) resolvedReturnType;
if (returnType.isArray()) {
returnType = returnType.getComponentType();
}
// gcode issue #508
if (void.class.equals(returnType)) {
ResultType rt = method.getAnnotation(ResultType.class);
if (rt != null) {
returnType = rt.value();
}
}
} else if (resolvedReturnType instanceof ParameterizedType) {
// 取出泛型的类型
ParameterizedType parameterizedType = (ParameterizedType) resolvedReturnType;
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
if (Collection.class.isAssignableFrom(rawType) || Cursor.class.isAssignableFrom(rawType)) {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
// 注意这里只会处理泛型个数为1个的
if (actualTypeArguments != null && actualTypeArguments.length == 1) {
Type returnTypeParameter = actualTypeArguments[0];
// 泛型类型为实体模型类
if (returnTypeParameter instanceof Class<?>) {
returnType = (Class<?>) returnTypeParameter;
}
// 套娃泛型
else if (returnTypeParameter instanceof ParameterizedType) {
// (gcode issue #443) actual type can be a also a parameterized type
returnType = (Class<?>) ((ParameterizedType) returnTypeParameter).getRawType();
}
// 泛型数组
else if (returnTypeParameter instanceof GenericArrayType) {
Class<?> componentType = (Class<?>) ((GenericArrayType) returnTypeParameter).getGenericComponentType();
// (gcode issue #525) support List<byte[]>
returnType = Array.newInstance(componentType, 0).getClass();
}
}
@MapKey("id")
@ResultType(Department.class)
@Select("select * from tbl_department")
Map<String, Department> findAllUseMap();
} else if (method.isAnnotationPresent(MapKey.class) && Map.class.isAssignableFrom(rawType)) {
// (gcode issue 504) Do not look into Maps if there is not MapKey annotation
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
// 泛型个数必须为2个
if (actualTypeArguments != null && actualTypeArguments.length == 2) {
// 解析第1个,即value类型
Type returnTypeParameter = actualTypeArguments[1];
if (returnTypeParameter instanceof Class<?>) {
returnType = (Class<?>) returnTypeParameter;
} else if (returnTypeParameter instanceof ParameterizedType) {
// (gcode issue 443) actual type can be a also a parameterized type
returnType = (Class<?>) ((ParameterizedType) returnTypeParameter).getRawType();
}
}
} else if (Optional.class.equals(rawType)) {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Type returnTypeParameter = actualTypeArguments[0];
if (returnTypeParameter instanceof Class<?>) {
returnType = (Class<?>) returnTypeParameter;
}
}
}
return returnType;
}