之前调试时,发现1个问题,就是mapperRegistry找不到对象
后来发现是mapper.xml的namespace里面的类名写得不对,然后来重新debug下
---
断点在
stop in org.apache.ibatis.builder.xml.XMLMapperBuilder.bindMapperForNamespace
调试
private void bindMapperForNamespace() { // 看到这里了 String namespace = builderAssistant.getCurrentNamespace(); System.out.println("namespace--->"+namespace); if (namespace != null) { // 如果设置了 Class boundType = null; try { // 看看是不是类 boundType = Resources.classForName(namespace); } catch (ClassNotFoundException e) { // ignore, bound type is not required } //如果真的是类/接口 if (boundType != null) { System.out.println("boundType--->"+boundType); //之前没有绑定 if (!configuration.hasMapper(boundType)) { // Spring may not know the real resource name so we set a // flag // to prevent loading again this resource from the mapper // interface // look at MapperAnnotationBuilder#loadXmlResource //关键这里 configuration.addLoadedResource("namespace:" + namespace); configuration.addMapper(boundType); } } } }
可以看到,关键就是
configuration.addLoadedResource("namespace:" + namespace); configuration.addMapper(boundType);
跟进去
第1行就是标记这个资源加载过了,见下图
319 loadedResources.add(resource);main[1] print loadedResources loadedResources = "[mysql_mapper.xml]"main[1] step> Step completed: "thread=main", org.apache.ibatis.session.Configuration.addLoadedResource(), line=320 bci=11320 }main[1] print loadedResources loadedResources = "[mysql_mapper.xml, namespace:interfaces.RoleMapper]"
看第2行
configuration.addMapper(boundType);
publicvoid addMapper(Class type) { // 交给mapperRegistry负责 mapperRegistry.addMapper(type); }
跟进去
publicvoid addMapper(Class type) { //这里开始 //还必须是接口 if (type.isInterface()) { //防止重复注册 if (hasMapper(type)) { throw new BindingException("Type " + type + " is already known to the MapperRegistry."); } // boolean loadCompleted = false; try { //开始注册 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); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }
这里继续跟踪
knownMappers.put(type, new MapperProxyFactory<T>(type));
/** * @author Lasse Voss */public class MapperProxyFactory{ // 接口类 private final Class mapperInterface; // 方法容器 private final Map methodCache = new ConcurrentHashMap (); public MapperProxyFactory(Class mapperInterface) { // 设置接口类 this.mapperInterface = mapperInterface; //end }
---然后就剩下
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();先看MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
然后就是parse解析过程了
---public void parse() { // 开始解析 String resource = type.toString(); // 如果没有加载过 if (!configuration.isResourceLoaded(resource)) { // 进来 // 这1行不执行 loadXmlResource(); // 标记已经加载过了 configuration.addLoadedResource(resource); // assistant.setCurrentNamespace(type.getName()); // 继续执行 // 下面2行注释掉 parseCache(); parseCacheRef(); //正式 //获取类的方法 Method[] methods = type.getMethods(); //遍历每1个方法 for (Method method : methods) { // try { // issue #237 //如果不是bridge方法 if (!method.isBridge()) { //解析此方法 parseStatement(method); } } catch (IncompleteElementException e) { configuration.addIncompleteMethod(new MethodResolver(this, method)); } } } parsePendingMethods(); }
上面是注解解析的过程,暂且不表。