我們平常在使用mybatis的時候隻需要生成mapper接口和與其對應的xml檔案就行了,我們就可以把這個接口當作一個bean,可以往其他的bean中注入了。我們沒有實作mapper接口,為什麼可以使用接口中的方法呢?原因是雖然我們沒有實作接口,但是通過配置檔案,spring為我們生成了接口的代理類。
讓我們從配置檔案入手,從源碼中一探究竟。

MapperScannerConfigurer這個類是負責掃描mapper接口所在的包的,它把掃描到的接口解析成一個個的bean定義(BeanDefinition),來看一下源碼:
MapperScannerConfigurer實作了兩個重要接口,如圖所示。
實作BeanDefinitionRegistryPostProcessor接口,我們可以自定義注冊bean過程,要實作的方法是
postProcessBeanDefinitionRegistry()
實作InitializingBean接口的afterPropertiesSet()方法,可以在bean建立之後初始化的時候做一些操作。
現在進入MapperScannerConfigurer的postProcessBeanDefinitionRegistry()方法
該方法内部把掃描mapper接口的工作委托給了ClassPathMapperScanner類,該類繼承自ClassPathBeanDefinitionScanner,進入它的scan()方法:
ClassPathBeanDefinitionScanner中的doScan()方法:
doScan方法真正的負責生成bean定義。
ClassPathMapperScanner重載的doScan()方法:
重載的doScan方法對生成的mapper的bean定義做了進一步處理,進入processBeanDefinitions()方法:
紅色部分為該方法的核心,mapperInterface設定的值是mapper接口的帶包名的路徑名稱;
definition.setBeanClass()把原來的BeanClass的類型替換成了MapperFactoryBean類型,這個是Mapper接口加載定義階段最重要的一步。是生成代理類的關鍵。
檢視MapperFactoryBean的定義:
MapperFactoryBean實作了FactoryBean接口,實作了FactoryBean接口的類型在調用getBean(beanName)既通過名稱擷取對象時,傳回的對象不是本身類型的對象,而是通過實作接口中的getObject()方法傳回的對象。
MapperFactoryBean實作了FactoryBean接口InitializingBean接口,在對象初始化的時候會調用它的afterPropertiesSet方法,該方法中首先調用了checkDaoConfig()方法,MapperFactoryBean重載的checkDaoConfig()如下:
Configuration configuration = getSqlSession().getConfiguration();這一句中的getSqlSession()擷取的SqlSession
對象就是文章開頭的配置檔案中配置的。
Configuration 是一個重要的配置類
進入 configuration.addMapper(this.mapperInterface)方法中:
在configuration内部對Mapper的操作都委托給了mapperRegistry對象,進入它的addMapper(type)方法,這裡的參數type就是一個mapper接口的類型(如:com.st.mapper.UserMapper.java):
knownMappers.put(type, new MapperProxyFactory(type));這一步為我們建立了mapper 的代理工廠類對象,并把它放入了knownMappers這個Map中。MapperProxyFactory這個類我們下面再講。
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
這兩句完成了mapper接口對應的xml檔案的解析,xml檔案中的每一個方法都被解析成了一個MappedStatement對象(代碼太長,不再展開),并添加到了configuration對象中:
對上面的内容的總結:
mapper接口的定義在bean加載階段會被替換成MapperFactoryBean類型,在spring容器初始化的時候會給我們生成MapperFactoryBean類型的對象,在該對象生成的過程中調用afterPropertiesSet()方法,為我們生成了一個
MapperProxyFactory類型的對象存放于Configuration裡的MapperRegistry對象中,同時解析了mapper接口對應的xml檔案,把每一個方法解析成一個MappedStatement對象,存放于Configuration裡的mappedStatements
這個Map集合中。
下面看一下MapperFactoryBean的getObject()方法,看看mapper代理對象是如何生成的:
跟蹤代碼最後調用的是MapperRegistry.getMapper()方法給我們傳回了mapper代理對象。
現在來看一下MapperProxyFactory這個類:
MapperProxy是被代理的對象,看下這個類:
在invoke()方法中最終執行的是mapperMethod.execute(sqlSession, args);方法。
來看一下MapperMethod這個類:
execute()這個方法最終負責執行我們mapper接口中方法,它會判斷要執行的方法的類型,然後調用sqlSession對應的方法類型來執行,并放回結果。