Mybatis 解析Mapper(class)

SqlSessionFactory初始化: http://donald-draper.iteye.com/blog/2331917
Mybatis加载解析Mapper(xml)文件第一讲: http://donald-draper.iteye.com/blog/2333125
Mybatis加载解析Mapper(xml)文件第二讲: http://donald-draper.iteye.com/blog/2333191
在前面两篇中,我们谈到Mapper(xml)文件的加载解析,今天来看一下,当全局配置文件中Mapper的resource和url为空时,classs不为空时,如何处理Mapper xml,文件和class。
private void mapperElement(XNode parent)
        throws Exception
    {
        if(parent != null)
        {
            for(Iterator i$ = parent.getChildren().iterator(); i$.hasNext();)
            {
                XNode child = (XNode)i$.next();
                if("package".equals(child.getName()))
                {
                    String mapperPackage = child.getStringAttribute("name");
                    configuration.addMappers(mapperPackage);
                } else
                {
                    String resource = child.getStringAttribute("resource");
                    String url = child.getStringAttribute("url");
                    String mapperClass = child.getStringAttribute("class");
		    //根据配置的resource,解析Mapper
                    if(resource != null && url == null && mapperClass == null)
                    {
                        ErrorContext.instance().resource(resource);
			//加载Mapper的resource文件
                        InputStream inputStream = Resources.getResourceAsStream(resource);
		        构建XMLMapperBuilder
                        XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
                        mapperParser.parse();
                    } else
                    if(resource == null && url != null && mapperClass == null)
                    {
                        ErrorContext.instance().resource(url);
                        InputStream inputStream = Resources.getUrlAsStream(url);
			//url配置的解析,与resource相同
                        XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
                        mapperParser.parse();
                    } else
                    //根据配置的class,解析Mapper
                    if(resource == null && url == null && mapperClass != null)
                    {
                        Class mapperInterface = Resources.classForName(mapperClass);
			//mapperInterface信息添加到configuration
                        configuration.addMapper(mapperInterface);
                    } else
                    {
                        throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                    }
                }
            }

        }
    }

//Configuration
 
 public void addMapper(Class type)
    {
        mapperRegistry.addMapper(type);
    }

//MapperRegistry
public class MapperRegistry
{ public void addMapper(Class type)
    {
        boolean loadCompleted;
        if(!type.isInterface())
            break MISSING_BLOCK_LABEL_125;
        if(hasMapper(type))
            throw new BindingException((new StringBuilder()).append("Type ").append(type).append(" is already known to the MapperRegistry.").toString());
        loadCompleted = false;
	//添加Class与MapperProxyFactory的对应关系
        knownMappers.put(type, new MapperProxyFactory(type));
	//构造Mapperclass注解Builder类
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
	//解析注解
        parser.parse();
        loadCompleted = true;
        if(!loadCompleted)
            knownMappers.remove(type);
        break MISSING_BLOCK_LABEL_125;
        Exception exception;
        exception;
        if(!loadCompleted)
            knownMappers.remove(type);
        throw exception;
    }
    private Configuration config;
    //HashMap<Class,MapperProxyFactory>
    private final Map knownMappers = new HashMap();
}

//MapperProxyFactory,mapperInterface的代理工厂
public class MapperProxyFactory
{
    public MapperProxyFactory(Class mapperInterface)
    {
        methodCache = new ConcurrentHashMap();
        this.mapperInterface = mapperInterface;
    }
     protected Object newInstance(MapperProxy mapperProxy)
    {
        //代理生成实例
        return Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] {
            mapperInterface
        }, mapperProxy);
    }
    public Object newInstance(SqlSession sqlSession)
    {
        MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
    }
    private final Class mapperInterface;
    private Map methodCache;
}

//MapperProxy
public class MapperProxy
    implements InvocationHandler, Serializable
{
    public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache)
    {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
    }
    public Object invoke(Object proxy, Method method, Object args[])
        throws Throwable
    {
        if(java/lang/Object.equals(method.getDeclaringClass()))
        {
            return method.invoke(this, args);
        } else
        {
            MapperMethod mapperMethod = cachedMapperMethod(method);
            return mapperMethod.execute(sqlSession, args);
        }
    }
    private MapperMethod cachedMapperMethod(Method method)
    {
        MapperMethod mapperMethod = (MapperMethod)methodCache.get(method);
        if(mapperMethod == null)
        {
            mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
            methodCache.put(method, mapperMethod);
        }
        return mapperMethod;
    }

    private static final long serialVersionUID = -6424540398559729838L;
    private final SqlSession sqlSession;
    private final Class mapperInterface;
    //Map<Method,MapperMethod>,即二级缓存
    private final Map methodCache;
}

//MapperMethod
public class MapperMethod
{
  //方法签名
  public static class MethodSignature{
	 private final boolean returnsMany;
        private final boolean returnsMap;
        private final boolean returnsVoid;
        private final Class returnType;
        private final String mapKey;
        private final Integer resultHandlerIndex;
        private final Integer rowBoundsIndex;
        private final SortedMap params;
        private final boolean hasNamedParameters;
	public MethodSignature(Configuration configuration, Method method)
            throws BindingException
        {
            returnType = method.getReturnType();
            returnsVoid = Void.TYPE.equals(returnType);
            returnsMany = configuration.getObjectFactory().isCollection(returnType) || returnType.isArray();
            mapKey = getMapKey(method);
            returnsMap = mapKey != null;
            hasNamedParameters = hasNamedParams(method);
            rowBoundsIndex = getUniqueParamIndex(method, org/apache/ibatis/session/RowBounds);
            resultHandlerIndex = getUniqueParamIndex(method, org/apache/ibatis/session/ResultHandler);
            params = Collections.unmodifiableSortedMap(getParams(method, hasNamedParameters));
        }
	}
   //statement类型,SqlCommand
   public static class SqlCommand
    {
        private final String name;//select|insert|update|delete节点的全局id
        private final SqlCommandType type;
   }
   //参数Map
   public static class ParamMap extends HashMap
    {

        public Object get(Object key)
        {
            if(!super.containsKey(key))
                throw new BindingException((new StringBuilder()).append("Parameter '").append(key).append("' not found. Available parameters are ").append(keySet()).toString());
            else
                return super.get(key);
        }

        private static final long serialVersionUID = -2212268410512043556L;

        public ParamMap()
        {
        }
    }
    //method执行方法
    public Object execute(SqlSession sqlSession, Object args[])
    {
        Object result;
	//插入
        if(SqlCommandType.INSERT == command.getType())
        {
	    //将参数转换为SqlCommand对应的参数
            Object param = method.convertArgsToSqlCommandParam(args);
	    //执行插入,并包装返回结果
            result = rowCountResult(sqlSession.insert(command.getName(), param));
        } else
	//更新
        if(SqlCommandType.UPDATE == command.getType())
        {
	    //执行更新,并包装返回结果
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
        } else
	//删除
        if(SqlCommandType.DELETE == command.getType())
        {
            //执行删除,并包装返回结果
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
        } else
	//查询
        if(SqlCommandType.SELECT == command.getType())
        {
            if(method.returnsVoid() && method.hasResultHandler())
            {
	        //无返回结果
                executeWithResultHandler(sqlSession, args);
                result = null;
            } else
            if(method.returnsMany())
	       //返回结果为List
                result = executeForMany(sqlSession, args);
            else
            if(method.returnsMap())
            {
	        //返回结果为Map
                result = executeForMap(sqlSession, args);
            } else
            {
	        //返回结果为Object
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(command.getName(), param);
            }
        } else
        {
            throw new BindingException((new StringBuilder()).append("Unknown execution method for: ").append(command.getName()).toString());
        }
        if(result == null && method.getReturnType().isPrimitive() && !method.returnsVoid())
            throw new BindingException((new StringBuilder()).append("Mapper method '").append(command.getName()).append(" attempted to return null from a method with a primitive return type (").append(method.getReturnType()).append(").").toString());
        else
            return result;
    }
    //包装返回结果
    private Object rowCountResult(int rowCount)
    {
        Object result;
        if(method.returnsVoid())
            result = null;
        else
        if(java/lang/Integer.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType()))
            result = Integer.valueOf(rowCount);
        else
        if(java/lang/Long.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType()))
            result = Long.valueOf(rowCount);
        else
        if(java/lang/Boolean.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType()))
            result = Boolean.valueOf(rowCount > 0);
        else
            throw new BindingException((new StringBuilder()).append("Mapper method '").append(command.getName()).append("' has an unsupported return type: ").append(method.getReturnType()).toString());
        return result;
    }
    //无返回结果
     private void executeWithResultHandler(SqlSession sqlSession, Object args[])
    {
        MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
        if(Void.TYPE.equals(((ResultMap)ms.getResultMaps().get(0)).getType()))
            throw new BindingException((new StringBuilder()).append("method ").append(command.getName()).append(" needs either a @ResultMap annotation, a @ResultType annotation,").append(" or a resultType attribute in XML so a ResultHandler can be used as a parameter.").toString());
        Object param = method.convertArgsToSqlCommandParam(args);
        if(method.hasRowBounds())
        {
            RowBounds rowBounds = method.extractRowBounds(args);
            sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
        } else
        {
            sqlSession.select(command.getName(), param, method.extractResultHandler(args));
        }
    }
    //返回结果为List
    private Object executeForMany(SqlSession sqlSession, Object args[])
    {
        Object param = method.convertArgsToSqlCommandParam(args);
        List result;
        if(method.hasRowBounds())
        {
            RowBounds rowBounds = method.extractRowBounds(args);
            result = sqlSession.selectList(command.getName(), param, rowBounds);
        } else
        {
            result = sqlSession.selectList(command.getName(), param);
        }
        if(!method.getReturnType().isAssignableFrom(result.getClass()))
        {
            if(method.getReturnType().isArray())
                return ((Object) (convertToArray(result)));
            else
                return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
        } else
        {
            return result;
        }
    }
    //返回结果为Map
    private Map executeForMap(SqlSession sqlSession, Object args[])
    {
        Object param = method.convertArgsToSqlCommandParam(args);
        Map result;
        if(method.hasRowBounds())
        {
            RowBounds rowBounds = method.extractRowBounds(args);
            result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds);
        } else
        {
            result = sqlSession.selectMap(command.getName(), param, method.getMapKey());
        }
        return result;
    }
    private final SqlCommand command;//method,对应的statement的描述
    private final MethodSignature method;//方法签名
}


从上可以看出Configuration添加MapperInterface,就是MapperRegistry注册到其
HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,
生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存;MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法。


现在回到MapperInterface,class的注解
//MapperAnnotationBuilder,MapperInterface的注解处理
public class MapperAnnotationBuilder
{
    private final Set sqlAnnotationTypes = new HashSet();
    private final Set sqlProviderAnnotationTypes = new HashSet();
    private Configuration configuration;
    private MapperBuilderAssistant assistant;//Mapper助手
    private Class type;//MapperInterface Type
    public MapperAnnotationBuilder(Configuration configuration, Class type)
    {
        String resource = (new StringBuilder()).append(type.getName().replace('.', '/')).append(".java (best guess)").toString();
        assistant = new MapperBuilderAssistant(configuration, resource);
        this.configuration = configuration;
        this.type = type;
        sqlAnnotationTypes.add(org/apache/ibatis/annotations/Select);
        sqlAnnotationTypes.add(org/apache/ibatis/annotations/Insert);
        sqlAnnotationTypes.add(org/apache/ibatis/annotations/Update);
        sqlAnnotationTypes.add(org/apache/ibatis/annotations/Delete);
        sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/SelectProvider);
        sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/InsertProvider);
        sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/UpdateProvider);
        sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/DeleteProvider);
    }
    //解析Mapper XML文件
    public void parse()
    {
        
        String resource = type.toString();
        if(!configuration.isResourceLoaded(resource))
        {
	    //如果configuration,未加载type对应的Mapper XML文件,
	    //则加载对应的XML文件
	    //加载mapInterface,package路径下的Mapper xml文件 
            loadXmlResource();
            //Configuration,添加Mapper xml文件资源id,到Set<String> loadedResources;
	    //Key为class的完整名(com.mapper.userMapper)
            configuration.addLoadedResource(resource);
	    //设置MapperBuilderAssistant的命名空间
            assistant.setCurrentNamespace(type.getName());
	    //解析注解缓存配置信息,并添加的Configuration,Cache Set 
            parseCache();
	    //解析缓存参考注解
            parseCacheRef();
            Method methods[] = type.getMethods();
            Method arr$[] = methods;
            int len$ = arr$.length;
            for(int i$ = 0; i$ < len$; i$++)
            {
                Method method = arr$[i$];
                try
                {
		    //遍历所有方法,解析方法注解
                    parseStatement(method);
                }
                catch(IncompleteElementException e)
                {
		    //如果缓存参考没有解决,则抛出IncompleteElementException,并将MethodResolver,
		    //添加到configuration的LinkedList<MethodResolver> incompleteMethod中
                    configuration.addIncompleteMethod(new MethodResolver(this, method));
                }
            }

        }
	//将方法从configuration的IncompleteMethods集合中移除
        parsePendingMethods();
    }
}
//如果configuration,未加载type对应的Mapper XML文件,
//加载mapInterface,package路径下的Mapper xml文件 
loadXmlResource();
    private void loadXmlResource()
    {
        //如果configuration,未加载type对应的Mapper XML文件,
        if(!configuration.isResourceLoaded((new StringBuilder()).append("namespace:").append(type.getName()).toString()))
        {
            String xmlResource = (new StringBuilder()).append(type.getName().replace('.', '/')).append(".xml").toString();
            InputStream inputStream = null;
            try
            {
	        //加载包路径下的Mapper xml文件,文件名为type.getName().replace('.', '/').append(".xml").toString()
		//com.mapper.userMapper.class
		//com/mapper/userMapper.xml
                inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
            }
            if(inputStream != null)
            {
	        //这个XML文件的解析,我们在上两篇文章已经讲过
                XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
                xmlParser.parse();
            }
        }
    }


//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
configuration.addLoadedResource(resource);

//Configuration
  public void addLoadedResource(String resource)
    {
        loadedResources.add(resource);
    }



//设置MapperBuilderAssistant的命名空间
assistant.setCurrentNamespace(type.getName());

//MapperBuilderAssistant
public class MapperBuilderAssistant extends BaseBuilder
{
    private String currentNamespace;//缓存命名空间
    private String resource;//Mapper xml文件url
    private Cache currentCache;//当前缓存
    private boolean unresolvedCacheRef;//缓存引用是否解决
    public MapperBuilderAssistant(Configuration configuration, String resource)
    {
        super(configuration);
        ErrorContext.instance().resource(resource);
        this.resource = resource;
    }
    //设置Mapper对应的命名空间
    public void setCurrentNamespace(String currentNamespace)
    {
        if(currentNamespace == null)
            throw new BuilderException("The mapper element requires a namespace attribute to be specified.");
        if(this.currentNamespace != null && !this.currentNamespace.equals(currentNamespace))
        {
            throw new BuilderException((new StringBuilder()).append("Wrong namespace. Expected '").append(this.currentNamespace).append("' but found '").append(currentNamespace).append("'.").toString());
        } else
        {
            this.currentNamespace = currentNamespace;
            return;
        }
    }
}


//解析注解缓存配置信息,并添加的Configuration,Cache Set
parseCache();

//解析CacheNamespace注解
     private void parseCache()
    {
        CacheNamespace cacheDomain = (CacheNamespace)type.getAnnotation(org/apache/ibatis/annotations/CacheNamespace);
        if(cacheDomain != null)
            assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), Long.valueOf(cacheDomain.flushInterval()), Integer.valueOf(cacheDomain.size()), cacheDomain.readWrite(), null);
    }


//MapperBuilderAssistant
//将缓存添加到Configuration的二级缓存中
 public Cache useNewCache(Class typeClass, Class evictionClass, Long flushInterval, Integer size, boolean readWrite, Properties props)
    {
        //获取缓存类型
        typeClass = (Class)valueOrDefault(typeClass, org/apache/ibatis/cache/impl/PerpetualCache);
	//获取缓存算法类型
        evictionClass = (Class)valueOrDefault(evictionClass, org/apache/ibatis/cache/decorators/LruCache);
	//构建缓存
        Cache cache = (new CacheBuilder(currentNamespace)).implementation(typeClass).addDecorator(evictionClass).clearInterval(flushInterval).size(size).readWrite(readWrite).properties(props).build();
        //将缓存添加到Configuration的二级缓存中
	configuration.addCache(cache);
        currentCache = cache;
        return cache;
    }


//CacheBuilder
public class CacheBuilder
{
    private String id;
    private Class implementation;//缓存实现类
    private List decorators;//缓存解码器
    private Integer size;
    private Long clearInterval;//刷新间隔
    private boolean readWrite;//是否可读写
    private Properties properties;
    public CacheBuilder(String id)
}


//Configuration
//将缓存添加到Configuration的二级缓存中
//StrictMap<currentNamespace,CacheBuilder>
//caches = new StrictMap("Caches collection");
 public void addCache(Cache cache)
    {
        caches.put(cache.getId(), cache);
    }

从上的分析可以看出@CacheNamespace的解析,实际上是,获取@CacheNamespace的type对应的Class,@CacheNamespace的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>


//解析缓存参考注解
parseCacheRef();

  
 //解析CacheNamespaceRef注解
    private void parseCacheRef()
    {
        CacheNamespaceRef cacheDomainRef = (CacheNamespaceRef)type.getAnnotation(org/apache/ibatis/annotations/CacheNamespaceRef);
        if(cacheDomainRef != null)
            assistant.useCacheRef(cacheDomainRef.value().getName());
    }

//MapperBuilderAssistant,
public Cache useCacheRef(String namespace)
    {
        if(namespace == null)
            throw new BuilderException("cache-ref element requires a namespace attribute.");
        Cache cache;
        unresolvedCacheRef = true;
	//根据命名空间,从configuration而级缓存中,获取缓存
        cache = configuration.getCache(namespace);
        if(cache == null)
            throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString());
        //从这里可以看出,参考命名的缓存必须存在,否则抛出异常
	currentCache = cache;
        unresolvedCacheRef = false;
        return cache;
        IllegalArgumentException e;
        e;
        throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString(), e);
    }

从分析@CacheNamespaceRef的解析,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException;

//遍历所有方法,解析方法注解
parseStatement(method);

//处理Statement方法method
void parseStatement(Method method)
    {
       //获取Method参数类型
        Class parameterTypeClass = getParameterType(method);
	//获取Method的LanguageDriver
        LanguageDriver languageDriver = getLanguageDriver(method);
        SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
        if(sqlSource != null)
        {
            Options options = (Options)method.getAnnotation(org/apache/ibatis/annotations/Options);
	    //构造mappedStatementId
            String mappedStatementId = (new StringBuilder()).append(type.getName()).append(".").append(method.getName()).toString();
            Integer fetchSize = null;
            Integer timeout = null;
	    //statementType,为PREPARED
            StatementType statementType = StatementType.PREPARED;
	    //resultSetType为FORWARD_ONLY
            ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
	    //获取Method的SQL类型
            SqlCommandType sqlCommandType = getSqlCommandType(method);
	    //是否是SELECT类型
            boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
	    //是否刷新缓存,如果不是SELECT,则刷新缓存,否,不刷新缓存
            boolean flushCache = !isSelect;
	    //是否用缓存,SELECT则用缓存,否,不用缓存
            boolean useCache = isSelect;
	    //默认 keyProperty为id;
            String keyProperty = "id";
            String keyColumn = null;
            KeyGenerator keyGenerator;
	    //如果是SQL是INSERT类型,isUseGeneratedKeys属性获取对应的keyGenerator,
	    //keyGenerator,这个我们在后文中,再讲
            if(SqlCommandType.INSERT.equals(sqlCommandType))
            {
	        //获取@SelectKey信息
                SelectKey selectKey = (SelectKey)method.getAnnotation(org/apache/ibatis/annotations/SelectKey);
                if(selectKey != null)
                {
		   
                    keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
                    //获取keyProperty从@SelectKey
		    keyProperty = selectKey.keyProperty();
                } else
                if(options == null)
                {
                    keyGenerator = ((KeyGenerator) (configuration.isUseGeneratedKeys() ? ((KeyGenerator) (new Jdbc3KeyGenerator())) : ((KeyGenerator) (new NoKeyGenerator()))));
                } else
                {
                    keyGenerator = ((KeyGenerator) (options.useGeneratedKeys() ? ((KeyGenerator) (new Jdbc3KeyGenerator())) : ((KeyGenerator) (new NoKeyGenerator()))));
                    keyProperty = options.keyProperty();
                    keyColumn = options.keyColumn();
                }
            } else
            {
                keyGenerator = new NoKeyGenerator();
            }
            if(options != null)
            {
	        //根据Options注解信息,获取flushCache,useCache,fetchSize,timeout,statementType,resultSetType等信息
                flushCache = options.flushCache();
                useCache = options.useCache();
                fetchSize = options.fetchSize() <= -1 && options.fetchSize() != -2147483648 ? null : Integer.valueOf(options.fetchSize());
                timeout = options.timeout() <= -1 ? null : Integer.valueOf(options.timeout());
                statementType = options.statementType();
                resultSetType = options.resultSetType();
            }
            String resultMapId = null;
	    //获取ResultMap注解信息
            ResultMap resultMapAnnotation = (ResultMap)method.getAnnotation(org/apache/ibatis/annotations/ResultMap);
            if(resultMapAnnotation != null)
                resultMapId = resultMapAnnotation.value();
            else
            if(isSelect)
	        //解析method的resultMap
                resultMapId = parseResultMap(method);
            //根据方法的注解信息,构建MappedStatement
	    //并添加到configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>
            assistant.addMappedStatement(mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout, null, parameterTypeClass, resultMapId, getReturnType(method), resultSetType, flushCache, useCache, false, keyGenerator, keyProperty, keyColumn, null, languageDriver);
        }
    }

//获取Method参数类型
    private Class getParameterType(Method method)
    {
        Class parameterType = null;
        Class parameterTypes[] = method.getParameterTypes();
        for(int i = 0; i < parameterTypes.length; i++)
        {
            if(org/apache/ibatis/session/RowBounds.isAssignableFrom(parameterTypes[i]))
                continue;
            if(parameterType == null)
                parameterType = parameterTypes[i];
            else
                parameterType = java/util/Map;
        }
        return parameterType;
    }
//获取Method的LanguageDriver
     private LanguageDriver getLanguageDriver(Method method)
    {
        Lang lang = (Lang)method.getAnnotation(org/apache/ibatis/annotations/Lang);
        if(lang != null)
        {
            Class languageDriverClass = lang.value();
            return configuration.getLanguageRegistry().getDriver(languageDriverClass);
        } else
        {
            return configuration.getLanguageRegistry().getDefaultDriver();
        }
    }
  //获取Method的SQL类型
    private SqlCommandType getSqlCommandType(Method method)
    {
        Class type = getSqlAnnotationType(method);
        if(type == null)
        {
            type = getSqlProviderAnnotationType(method);
            if(type == null)
                return SqlCommandType.UNKNOWN;
            if(type == org/apache/ibatis/annotations/SelectProvider)
                type = org/apache/ibatis/annotations/Select;
            else
            if(type == org/apache/ibatis/annotations/InsertProvider)
                type = org/apache/ibatis/annotations/Insert;
            else
            if(type == org/apache/ibatis/annotations/UpdateProvider)
                type = org/apache/ibatis/annotations/Update;
            else
            if(type == org/apache/ibatis/annotations/DeleteProvider)
                type = org/apache/ibatis/annotations/Delete;
        }
        return SqlCommandType.valueOf(type.getSimpleName().toUpperCase(Locale.ENGLISH));
    }
 
// 方法的@SelectKey,解析处理,下面是xml配置,以辅助理解
<!-- 对应userDao中的insertUser方法,  -->
   <insert id="insertUser" parameterType="com.dy.entity.User">
	    <!-- oracle等不支持id自增长的,可根据其id生成策略,先获取id -->      
	  <selectKey resultType="int" order="BEFORE" keyProperty="id">
		  select seq_user_id.nextval as id from dual  </selectKey>

	     insert into user(id, name, password, age, deleteFlag) 
		   values(#{id}, #{name}, #{password}, #{age}, #{deleteFlag})
</insert>


//根据SelectKeyAnnotation信息,获取KeyGenerator
   
 private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId, Class parameterTypeClass, LanguageDriver languageDriver)
    {
        String id = (new StringBuilder()).append(baseStatementId).append("!selectKey").toString();
        //keyProperty Type
	Class resultTypeClass = selectKeyAnnotation.resultType();
	//statementType
        StatementType statementType = selectKeyAnnotation.statementType();
        String keyProperty = selectKeyAnnotation.keyProperty();
        boolean executeBefore = selectKeyAnnotation.before();
        boolean useCache = false;
        KeyGenerator keyGenerator = new NoKeyGenerator();
        Integer fetchSize = null;//抓取大小
        Integer timeout = null;//超时时间
        boolean flushCache = false;//是否刷新缓存
        String parameterMap = null;
        String resultMap = null;
        ResultSetType resultSetTypeEnum = null;
        SqlSource sqlSource = buildSqlSourceFromStrings(selectKeyAnnotation.statement(), parameterTypeClass, languageDriver);
        SqlCommandType sqlCommandType = SqlCommandType.SELECT;
	//根据@SelectKey信息,构造MappedStatement,并添加到configuration中mappedStatements Map中
        assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, false, keyGenerator, keyProperty, null, null, languageDriver);
        id = assistant.applyCurrentNamespace(id, false);
        org.apache.ibatis.mapping.MappedStatement keyStatement = configuration.getMappedStatement(id, false);
        SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore);
        //将SelectKeyGenerator的命名空间id与KeyGenerator映射关系,添加到Configuration
	configuration.addKeyGenerator(id, answer);
        return answer;
    }
}

//Configuration
public void addKeyGenerator(String id, KeyGenerator keyGenerator)
    {
        //StrictMap<String,KeyGenerator> key为KeyGenerator的nameSpace id
        keyGenerators.put(id, keyGenerator);
    }

现在回到
parseStatement(Method method)的ResultMap的处理

//解析method的@ResultMap
  
 private String parseResultMap(Method method)
    {
        Class returnType = getReturnType(method);
        ConstructorArgs args = (ConstructorArgs)method.getAnnotation(org/apache/ibatis/annotations/ConstructorArgs);
        Results results = (Results)method.getAnnotation(org/apache/ibatis/annotations/Results);
        TypeDiscriminator typeDiscriminator = (TypeDiscriminator)method.getAnnotation(org/apache/ibatis/annotations/TypeDiscriminator);
        //方法返回结果唯一id
	String resultMapId = generateResultMapName(method);
	//委托给applyResultMap方法
        applyResultMap(resultMapId, returnType, argsIf(args), resultsIf(results), typeDiscriminator);
        return resultMapId;
    }  
    private void applyResultMap(String resultMapId, Class returnType, Arg args[], Result results[], TypeDiscriminator discriminator)
    {
        List resultMappings = new ArrayList();
        applyConstructorArgs(args, returnType, resultMappings);
        applyResults(results, returnType, resultMappings);
        Discriminator disc = applyDiscriminator(resultMapId, returnType, discriminator);
	//构造ResultMap,并将ResultMap映射关系添加到configuration
        assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null);
        createDiscriminatorResultMaps(resultMapId, returnType, discriminator);
    }
    //解析@Results注解信息,根据注解信息,构造,并添加到resultMappings
      private void applyResults(Result results[], Class resultType, List resultMappings)
    {
        Result arr$[] = results;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            Result result = arr$[i$];
            ArrayList flags = new ArrayList();
            if(result.id())
                flags.add(ResultFlag.ID);
            org.apache.ibatis.mapping.ResultMapping resultMapping = assistant.buildResultMapping(resultType, nullOrEmpty(result.property()), nullOrEmpty(result.column()), result.javaType() != Void.TYPE ? result.javaType() : null, result.jdbcType() != JdbcType.UNDEFINED ? result.jdbcType() : null, hasNestedSelect(result) ? nestedSelectId(result) : null, null, null, null, result.typeHandler() != org/apache/ibatis/type/UnknownTypeHandler ? result.typeHandler() : null, flags);
            resultMappings.add(resultMapping);
        }
    }
    //返回ReturnType的Class
    private Class getReturnType(Method method)
    {
        Class returnType = method.getReturnType();
        if(Void.TYPE.equals(returnType))
        {
            ResultType rt = (ResultType)method.getAnnotation(org/apache/ibatis/annotations/ResultType);
            if(rt != null)
                returnType = rt.value();
        } else
        if(java/util/Collection.isAssignableFrom(returnType))
        {
            Type returnTypeParameter = method.getGenericReturnType();
            if(returnTypeParameter instanceof ParameterizedType)
            {
                Type actualTypeArguments[] = ((ParameterizedType)returnTypeParameter).getActualTypeArguments();
                if(actualTypeArguments != null && actualTypeArguments.length == 1)
                {
                    returnTypeParameter = actualTypeArguments[0];
                    if(returnTypeParameter instanceof Class)
                        returnType = (Class)returnTypeParameter;
                    else
                    if(returnTypeParameter instanceof ParameterizedType)
                        returnType = (Class)((ParameterizedType)returnTypeParameter).getRawType();
                    else
                    if(returnTypeParameter instanceof GenericArrayType)
                    {
                        Class componentType = (Class)((GenericArrayType)returnTypeParameter).getGenericComponentType();
                        returnType = Array.newInstance(componentType, 0).getClass();
                    }
                }
            }
        } else
        if(method.isAnnotationPresent(org/apache/ibatis/annotations/MapKey) && java/util/Map.isAssignableFrom(returnType))
        {
            Type returnTypeParameter = method.getGenericReturnType();
            if(returnTypeParameter instanceof ParameterizedType)
            {
                Type actualTypeArguments[] = ((ParameterizedType)returnTypeParameter).getActualTypeArguments();
                if(actualTypeArguments != null && actualTypeArguments.length == 2)
                {
                    returnTypeParameter = actualTypeArguments[1];
                    if(returnTypeParameter instanceof Class)
                        returnType = (Class)returnTypeParameter;
                    else
                    if(returnTypeParameter instanceof ParameterizedType)
                        returnType = (Class)((ParameterizedType)returnTypeParameter).getRawType();
                }
            }
        }
        return returnType;
    }

再来看
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver);

  
//MapperBuilderAssistant
public class MapperBuilderAssistant extends BaseBuilder
{

    //添加MappedStatement到Configuration
     public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType, SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap, 
            Class parameterType, String resultMap, Class resultType, ResultSetType resultSetType, boolean flushCache, boolean useCache, boolean resultOrdered, 
            KeyGenerator keyGenerator, String keyProperty, String keyColumn, String databaseId, LanguageDriver lang)
    {
        if(unresolvedCacheRef)
        {
	     //如果缓存参考没有解决,则抛出IncompleteElementException
            throw new IncompleteElementException("Cache-ref not yet resolved");
        } else
        {
            id = applyCurrentNamespace(id, false);
            boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
            org.apache.ibatis.mapping.MappedStatement.Builder statementBuilder = new org.apache.ibatis.mapping.MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType);
            //配置MappedStatement.Builder属性
	    statementBuilder.resource(resource);
            statementBuilder.fetchSize(fetchSize);
            statementBuilder.statementType(statementType);
            statementBuilder.keyGenerator(keyGenerator);
            statementBuilder.keyProperty(keyProperty);
            statementBuilder.keyColumn(keyColumn);
            statementBuilder.databaseId(databaseId);
            statementBuilder.lang(lang);
            statementBuilder.resultOrdered(resultOrdered);
            setStatementTimeout(timeout, statementBuilder);
	    //设置Statement的parameterMap
            setStatementParameterMap(parameterMap, parameterType, statementBuilder);
	    //设置Statement的resultMap
            setStatementResultMap(resultMap, resultType, resultSetType, statementBuilder);
	     //设置Statement缓存信息
            setStatementCache(isSelect, flushCache, useCache, currentCache, statementBuilder);
	    //构建MappedStatement
            MappedStatement statement = statementBuilder.build();
	    //添加MappedStatement到Configuration
            configuration.addMappedStatement(statement);
            return statement;
        }
    }
}

//添加MappedStatement到Configuration
mappedStatements = new StrictMap("Mapped Statements collection");
public void addMappedStatement(MappedStatement ms)
    { 
        StrictMap<String,MappedStatement>,key为MappedStatement的id
        mappedStatements.put(ms.getId(), ms);
    }


//MappedStatement
public final class MappedStatement
{
    public static class Builder
    {

        public MappedStatement build()
        {
            if(!$assertionsDisabled && mappedStatement.configuration == null)
                throw new AssertionError();
            if(!$assertionsDisabled && mappedStatement.id == null)
                throw new AssertionError();
            if(!$assertionsDisabled && mappedStatement.sqlSource == null)
                throw new AssertionError();
            if(!$assertionsDisabled && mappedStatement.lang == null)
            {
                throw new AssertionError();
            } else
            {
                mappedStatement.resultMaps = Collections.unmodifiableList(mappedStatement.resultMaps);
                return mappedStatement;
            }
        }

        private MappedStatement mappedStatement;
        static final boolean $assertionsDisabled = !org/apache/ibatis/mapping/MappedStatement.desiredAssertionStatus();
    }
   public BoundSql getBoundSql(Object parameterObject)
    {
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        List parameterMappings = boundSql.getParameterMappings();
        if(parameterMappings == null || parameterMappings.size() <= 0)
            boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
        Iterator i$ = boundSql.getParameterMappings().iterator();
        do
        {
            if(!i$.hasNext())
                break;
            ParameterMapping pm = (ParameterMapping)i$.next();
            String rmId = pm.getResultMapId();
            if(rmId != null)
            {
                ResultMap rm = configuration.getResultMap(rmId);
                if(rm != null)
                    hasNestedResultMaps |= rm.hasNestedResultMaps();
            }
        } while(true);
        return boundSql;
    }
    private String resource;
    private Configuration configuration;
    private String id;
    private Integer fetchSize;
    private Integer timeout;
    private StatementType statementType;
    private ResultSetType resultSetType;
    private SqlSource sqlSource;
    private Cache cache;
    private ParameterMap parameterMap;
    private List resultMaps;
    private boolean flushCacheRequired;
    private boolean useCache;
    private boolean resultOrdered;
    private SqlCommandType sqlCommandType;
    private KeyGenerator keyGenerator;
    private String keyProperties[];
    private String keyColumns[];
    private boolean hasNestedResultMaps;
    private String databaseId;
    private Log statementLog;
    private LanguageDriver lang;
}


从上可以看出解析@SelectKey信息,跟@SelectKey节点的属性信息,构建keyStatement,
并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,如果无@SelectKey,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据method方法注解信息和KeyGenerator,构造MapperStatement,
添加到configuration的mappedStatements的Map中并添加在configuration的keyGenerators-Map中


//遍历configuration的IncompleteMethods集合,重新解析MethodResolver
parsePendingMethods();
   private void parsePendingMethods()
    {
        Collection incompleteMethods = configuration.getIncompleteMethods();
        synchronized(incompleteMethods)
        {
            for(Iterator iter = incompleteMethods.iterator(); iter.hasNext();)
                try
                {
                    ((MethodResolver)iter.next()).resolve();
                    iter.remove();
                }
                catch(IncompleteElementException e) { }

        }
    }

//MethodResolver
public class MethodResolver
{
    public MethodResolver(MapperAnnotationBuilder annotationBuilder, Method method)
    {
        this.annotationBuilder = annotationBuilder;
        this.method = method;
    }
    public void resolve()
    {
        annotationBuilder.parseStatement(method);
    }
    private final MapperAnnotationBuilder annotationBuilder;
    private Method method;
}

总结:

MapperInterface的解析,首先Configuration添加MapperInterface,实质上MapperRegistry注册到其HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存,MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法;加载mapInterface,package路径下的Mapper xml文件,如果未加载,则加载解析;@CacheNamespace的解析,实际上是,获取@CacheNamespace的type对应的Class,@CacheNamespace的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>;@CacheNamespaceRef的解析,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,
不存在,则抛出IncompleteElementException;解析@SelectKey信息,跟@SelectKey节点的属性信息,构建keyStatement,并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,如果无@SelectKey,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据method方法注解信息和KeyGenerator,构造MapperStatement,添加到configuration的mappedStatements的Map中并添加在configuration的keyGenerators-Map中。



//ParameterMap
public class ParameterMap
{
    public static class Builder
    {
        public ParameterMap build()
        {
	   //获取不可修改的parameterMappings
            parameterMap.parameterMappings = Collections.unmodifiableList(parameterMap.parameterMappings);
            return parameterMap;
        }
    }
    private String id;
    private Class type;
    private List parameterMappings;
}

 
   
//ResultMap
public class ResultMap
{
    private String id;
    private Class type;
    private List resultMappings;
    private List idResultMappings;
    private List constructorResultMappings;
    private List propertyResultMappings;
    private Set mappedColumns;
    private Discriminator discriminator;
    private boolean hasNestedResultMaps;
    private boolean hasNestedQueries;
    private Boolean autoMapping;
    public static class Builder
    {
    public ResultMap build()
        {
            if(resultMap.id == null)
                throw new IllegalArgumentException("ResultMaps must have an id");
            resultMap.mappedColumns = new HashSet();
            resultMap.idResultMappings = new ArrayList();
            resultMap.constructorResultMappings = new ArrayList();
            resultMap.propertyResultMappings = new ArrayList();
            Iterator i$ = resultMap.resultMappings.iterator();
            do
            {
                if(!i$.hasNext())
                    break;
                ResultMapping resultMapping = (ResultMapping)i$.next();
                resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null;
                resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || resultMapping.getNestedResultMapId() != null;
                String column = resultMapping.getColumn();
                if(column != null)
                    resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));
                else
                if(resultMapping.isCompositeResult())
                {
                    Iterator i$ = resultMapping.getComposites().iterator();
                    do
                    {
                        if(!i$.hasNext())
                            break;
                        ResultMapping compositeResultMapping = (ResultMapping)i$.next();
                        String compositeColumn = compositeResultMapping.getColumn();
                        if(compositeColumn != null)
                            resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH));
                    } while(true);
                }
                if(resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR))
                    resultMap.constructorResultMappings.add(resultMapping);
                else
                    resultMap.propertyResultMappings.add(resultMapping);
                if(resultMapping.getFlags().contains(ResultFlag.ID))
                    resultMap.idResultMappings.add(resultMapping);
            } while(true);
            if(resultMap.idResultMappings.isEmpty())
                resultMap.idResultMappings.addAll(resultMap.resultMappings);
            resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings);
            resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings);
            resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings);
            resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings);
            resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns);
            return resultMap;
        }
   }
}

//BoundSql
public class BoundSql
{
    private String sql;
    private List parameterMappings;
    private Object parameterObject;
    private Map additionalParameters;
    private MetaObject metaParameters;
    public BoundSql(Configuration configuration, String sql, List parameterMappings, Object parameterObject)
    {
        this.sql = sql;
        this.parameterMappings = parameterMappings;
        this.parameterObject = parameterObject;
        additionalParameters = new HashMap();
        metaParameters = configuration.newMetaObject(additionalParameters);
    }
}

//MetaObject
public class MetaObject
{
    private Object originalObject;
    private ObjectWrapper objectWrapper;
    private ObjectFactory objectFactory;
    private ObjectWrapperFactory objectWrapperFactory;
    //设置MetaObject的name属性的值为value
    public void setValue(String name, Object value)
    {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if(prop.hasNext())
        {
            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
            if(metaValue == SystemMetaObject.NULL_META_OBJECT)
            {
                if(value == null && prop.getChildren() != null)
                    return;
                metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
            }
            metaValue.setValue(prop.getChildren(), value);
        } else
        {
            objectWrapper.set(prop, value);
        }
    }
}

//SqlCommandType
public final class SqlCommandType extends Enum
{
    public static final SqlCommandType UNKNOWN;
    public static final SqlCommandType INSERT;
    public static final SqlCommandType UPDATE;
    public static final SqlCommandType DELETE;
    public static final SqlCommandType SELECT;
    private static final SqlCommandType $VALUES[];
    static 
    {
        UNKNOWN = new SqlCommandType("UNKNOWN", 0);
        INSERT = new SqlCommandType("INSERT", 1);
        UPDATE = new SqlCommandType("UPDATE", 2);
        DELETE = new SqlCommandType("DELETE", 3);
        SELECT = new SqlCommandType("SELECT", 4);
        $VALUES = (new SqlCommandType[] {
            UNKNOWN, INSERT, UPDATE, DELETE, SELECT
        });
    }
}

//StatementTypes
public final class StatementType extends Enum
{
    public static final StatementType STATEMENT;
    public static final StatementType PREPARED;
    public static final StatementType CALLABLE;
    private static final StatementType $VALUES[];
    static 
    {
        STATEMENT = new StatementType("STATEMENT", 0);
        PREPARED = new StatementType("PREPARED", 1);
        CALLABLE = new StatementType("CALLABLE", 2);
        $VALUES = (new StatementType[] {
            STATEMENT, PREPARED, CALLABLE
        });
    }
}

//ResultSetType
public final class ResultSetType extends Enum
{
    public static final ResultSetType FORWARD_ONLY;
    public static final ResultSetType SCROLL_INSENSITIVE;
    public static final ResultSetType SCROLL_SENSITIVE;
    private int value;
    private static final ResultSetType $VALUES[];

    static 
    {
        FORWARD_ONLY = new ResultSetType("FORWARD_ONLY", 0, 1003);
        SCROLL_INSENSITIVE = new ResultSetType("SCROLL_INSENSITIVE", 1, 1004);
        SCROLL_SENSITIVE = new ResultSetType("SCROLL_SENSITIVE", 2, 1005);
        $VALUES = (new ResultSetType[] {
            FORWARD_ONLY, SCROLL_INSENSITIVE, SCROLL_SENSITIVE
        });
    }
}

猜你喜欢

转载自donald-draper.iteye.com/blog/2333293