Mapper 代理方式初始化  
首先修改一下 SqlSession  获取代理对象方式,即通过 getMapper()  来拿到动态代理对象   
public  class  MybatisTest  { 
  
  @Test 
  public  void  test2 ( )  throws  IOException  { 
    
    InputStream  resourceAsStream =  Resources . getResourceAsStream ( "sqlMapConfig.xml" ) ; 
    
    SqlSessionFactory  sqlSessionFactory =  new  SqlSessionFactoryBuilder ( ) . build ( resourceAsStream) ; 
    
    
    SqlSession  sqlSession =  sqlSessionFactory. openSession ( ) ; 
    
    UserMapper  mapperProxy =  sqlSession. getMapper ( UserMapper . class ) ; 
    . . . 
  } 
} 
  
修改 sqlMapConfig.xml  引入配置文件的方式   
< configuration>  
  ...
  
  < mappers>  
    < package  name = " com.itheima.mapper" />  
  </ mappers>  
</ configuration>  
  
把 UserMapper.xml  放到和 com.itheima.mapper.UserMapper  同一个目录,同时修改一下命名空间,然后就可以学习 MyBatis 的代理方式   
<! DOCTYPE  mapper 
  PUBLIC  "-//mybatis.org//DTD Mapper 3.0//EN" 
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >  
< mapper  namespace = " com.itheima.mapper.UserMapper" >  
  < cache> </ cache>  
  < select  id = " findByCondition"   resultType = " com.itheima.pojo.User"   useCache = " true" >  
    SELECT id, name FROM  user WHERE id = #{id}
  </ select>  
</ mapper>  
  
问题   
<package name=“com.itheima.mapper”/> 是如何进行解析的?   
首先解析配置文件还是从 SqlSessionFactoryBuilder  的 build()  开始,方法内会先创建 XMLConfigBuilder ,然后开始解析 sqlMapConfig.xml  配置文件   
public  class  SqlSessionFactoryBuilder  { 
  
  public  SqlSessionFactory  build ( InputStream  inputStream,  String  environment,  Properties  properties)  { 
    try  { 
      
      
      
      XMLConfigBuilder  parser =  new  XMLConfigBuilder ( inputStream,  environment,  properties) ; 
      
      
      
      return  build ( parser. parse ( ) ) ; 
    }  catch  ( Exception  e)  { 
      throw  ExceptionFactory . wrapException ( "Error building SqlSession." ,  e) ; 
    }  finally  { 
      ErrorContext . instance ( ) . reset ( ) ; 
      try  { 
        inputStream. close ( ) ; 
      }  catch  ( IOException  e)  { 
        
      } 
    } 
  } 
  
  public  SqlSessionFactory  build ( Configuration  config)  { 
    return  new  DefaultSqlSessionFactory ( config) ; 
  } 
} 
  
parse()  会继续先解析 /configuration  节点,然后从根节点开始找到每个节点进行解析  
public  class  XMLConfigBuilder  extends  BaseBuilder  { 
  private  boolean  parsed; 
  private  final  XPathParser  parser; 
  . . . 
  public  Configuration  parse ( )  { 
    if  ( parsed)  { 
      throw  new  BuilderException ( "Each XMLConfigBuilder can only be used once." ) ; 
    } 
    parsed =  true ; 
    
    
    parseConfiguration ( parser. evalNode ( "/configuration" ) ) ; 
    return  configuration; 
  } 
} 
  
这次我们更关注解析 /mappers  这个基点   
public  class  XMLConfigBuilder  extends  BaseBuilder  { 
  . . . 
  private  void  parseConfiguration ( XNode  root)  { 
    try  { 
      . . . 
      
      mapperElement ( root. evalNode ( "mappers" ) ) ; 
    }  catch  ( Exception  e)  { 
      throw  new  BuilderException ( "Error parsing SQL Mapper Configuration. Cause: "  +  e,  e) ; 
  } 
} 
  
获取 /mappers  标签,然后遍历 /mappers  标签的子标签,也就是现在我们配置的 /package  标签,从标签中拿到 name 属性,即 com.itheima.mapper,然后开始将包下所有的 mapper 接口以及它的代理工厂对象存储到 Configuration  的一个 Map  集合中,key 为 mapper 接口类型,value 为代理对象工厂   
public  abstract  class  BaseBuilder  { 
  protected  final  Configuration  configuration; 
  . . . 
  private  void  mapperElement ( XNode  parent)  throws  Exception  { 
    if  ( parent !=  null )  { 
      
      for  ( XNode  child :  parent. getChildren ( ) )  { 
        
        if  ( "package" . equals ( child. getName ( ) ) )  { 
          
          String  mapperPackage =  child. getStringAttribute ( "name" ) ; 
          
          configuration. addMappers ( mapperPackage) ; 
        }  else  { 
        . . . 
      } 
    } 
  } 
} 
  
Configuration  对象会交由 MapperRegistry  来添加到 Map  集合  
public  class  Configuration  { 
  . . . 
  protected  final  MapperRegistry  mapperRegistry =  new  MapperRegistry ( this ) ; 
  . . . 
  public  void  addMappers ( String  packageName)  { 
    
    mapperRegistry. addMappers ( packageName) ; 
  } 
} 
  
MapperRegistry  先创建解析工具类 ResolverUtil ,根据 packageName 找到该包下所有的 Mapper  接口文件,然后将 Mapper  接口添加到 MapperRegistry  中  
public  class  MapperRegistry  { 
  . . . 
  public  void  addMappers ( String  packageName,  Class < ? >   superType)  { 
    
    ResolverUtil < Class < ? > >   resolverUtil =  new  ResolverUtil < > ( ) ; 
    
    resolverUtil. find ( new  ResolverUtil. IsA ( superType) ,  packageName) ; 
    
    Set < Class < ?  extends  Class < ? > > >   mapperSet =  resolverUtil. getClasses ( ) ; 
    for  ( Class < ? >   mapperClass :  mapperSet)  { 
      
      addMapper ( mapperClass) ; 
    } 
  } 
} 
  
ResolverUtil  找接口时,先把 packageName 改成 com/itheima/mapper,然后查找所有的 .class  文件,然后加载这个文件存入 matches  中  
public  class  ResolverUtil < T >   { 
  
  private  Set < Class < ?  extends  T > >   matches =  new  HashSet < > ( ) ; 
  . . . 
  protected  String  getPackagePath ( String  packageName)  { 
    
    return  packageName ==  null  ?  null  :  packageName. replace ( '.' ,  '/' ) ; 
  } 
 
  public  ResolverUtil < T >   find ( Test  test,  String  packageName)  { 
    
    String  path =  getPackagePath ( packageName) ; 
    try  { 
      List < String >   children =  VFS. getInstance ( ) . list ( path) ; 
      for  ( String  child :  children)  { 
        if  ( child. endsWith ( ".class" ) )  { 
          
          addIfMatching ( test,  child) ; 
        } 
      } 
    }  catch  ( IOException  ioe)  { 
      log. error ( "Could not read package: "  +  packageName,  ioe) ; 
    } 
    return  this ; 
  } 
  
  protected  void  addIfMatching ( Test  test,  String  fqn)  { 
    try  { 
      
      String  externalName =  fqn. substring ( 0 ,  fqn. indexOf ( '.' ) ) . replace ( '/' ,  '.' ) ; 
      ClassLoader  loader =  getClassLoader ( ) ; 
      if  ( log. isDebugEnabled ( ) )  { 
        log. debug ( "Checking to see if class "  +  externalName +  " matches criteria ["  +  test +  "]" ) ; 
      } 
      
      Class < ? >   type =  loader. loadClass ( externalName) ; 
      if  ( test. matches ( type) )  { 
        
        matches. add ( ( Class < T > )  type) ; 
      } 
    }  catch  ( Throwable  t)  { 
      log. warn ( "Could not examine class '"  +  fqn +  "'"  +  " due to a " 
          +  t. getClass ( ) . getName ( )  +  " with message: "  +  t. getMessage ( ) ) ; 
    } 
  } 
} 
  
得到类集合之后,先判断对应的类是否已经加入过 knownMappers ,如果是,则抛出异常,否则就加入 knownMappers  中,其中 key 为 type ,value 为 MapperProxyFactory  代理工厂,如果接口中有使用 @Select  或者配置了 Mapper.xml ,就需要使用 MapperAnnotationBuilder  进一步解析   
public  class  MapperRegistry  { 
  private  final  Configuration  config; 
  private  final  Map < Class < ? > ,  MapperProxyFactory < ? > >   knownMappers =  new  HashMap < > ( ) ; 
  . . . 
  public  < T >   boolean  hasMapper ( Class < T >   type)  { 
    return  knownMappers. containsKey ( 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  { 
        
        knownMappers. put ( type,  new  MapperProxyFactory < > ( type) ) ; 
        
        MapperAnnotationBuilder  parser =  new  MapperAnnotationBuilder ( config,  type) ; 
        
        parser. parse ( ) ; 
        loadCompleted =  true ; 
      }  finally  { 
        if  ( ! loadCompleted)  { 
          knownMappers. remove ( type) ; 
        } 
      } 
    } 
  } 
} 
  
解析 Mapper.xml  时,先获取 mapper 接口的全路径(即 interface com.itheima.mapper.UserMapper)。如果 Configuration  对象从来没加载过,就创建 XMLMapperBuilder  来解析。然后遍历 type 的每个方法,都解析构成 MappedStatement  对象,存入 Configuration  对象中   
public  class  MapperAnnotationBuilder  { 
  
  private  final  Configuration  configuration; 
  private  final  MapperBuilderAssistant  assistant; 
  private  final  Class < ? >   type; 
  . . . 
  public  void  parse ( )  { 
    
    String  resource =  type. toString ( ) ; 
    
    if  ( ! configuration. isResourceLoaded ( resource) )  { 
      
      loadXmlResource ( ) ; 
      
      configuration. addLoadedResource ( resource) ; 
      assistant. setCurrentNamespace ( type. getName ( ) ) ; 
      
      parseCache ( ) ; 
      
      parseCacheRef ( ) ; 
      
      for  ( Method  method :  type. getMethods ( ) )  { 
        if  ( ! canHaveStatement ( method) )  { 
          continue ; 
        } 
        if  ( getAnnotationWrapper ( method,  false ,  Select . class ,  SelectProvider . class ) . isPresent ( ) 
            &&  method. getAnnotation ( ResultMap . class )  ==  null )  { 
          parseResultMap ( method) ; 
        } 
        try  { 
          
          parseStatement ( method) ; 
        }  catch  ( IncompleteElementException  e)  { 
          configuration. addIncompleteMethod ( new  MethodResolver ( this ,  method) ) ; 
        } 
      } 
    } 
    parsePendingMethods ( ) ; 
  } 
  
  void  parseStatement ( Method  method)  { 
    
    final  Class < ? >   parameterTypeClass =  getParameterType ( method) ; 
    . . . 
    
    assistant. addMappedStatement ( 
          mappedStatementId, 
          sqlSource, 
          statementType, 
          sqlCommandType, 
          fetchSize, 
          timeout, 
          
          null , 
          parameterTypeClass, 
          resultMapId, 
          getReturnType ( method) , 
          resultSetType, 
          flushCache, 
          useCache, 
          
          false , 
          keyGenerator, 
          keyProperty, 
          keyColumn, 
          statementAnnotation. getDatabaseId ( ) , 
          languageDriver, 
          
          options !=  null  ?  nullOrEmpty ( options. resultSets ( ) )  :  null ) ; 
    } ) ; 
  } 
} 
  
总结