MyBatis 執行流程及源碼解析


咱們在平常工做中普遍使用mybatis做爲數據持久層框架, 可是mybatis的執行流程是怎麼樣的,你瞭解過嗎。本文將從源碼角度,帶你分析mybatis的工做原理。


先看一個簡單的例子,以Service調用Mapper接口爲例:java





public interface StudentMapper {    @Select("select * from student")    public List<Map<String,Object>> query();}










@Service("studentService")public class StudentServiceImpl implements StudentService {    @Autowired    StudentMapper studentMapper;
   @Override    public List<Map<String, Object>> query() {        return studentMapper.select();    }}

向Service中注入這個Mapper並調用時,你知道這時注入的是什麼嗎?spring


圖片


經過調試,能夠知道這時實際的studentMapper是一個類型爲MapperProxy的代理對象,下面將從myabtis環境初始化開始,具體分析代理對象的產生過程。(不熟悉代理對象的同窗,能夠查看以前專門講java代理的文章)sql


1、配置SqlSessionFactoryBean 時都作了什麼?mybatis


在進行spring和mybatis整合時,會用xml或者註解的方式去配置一個SqlSessionFactoryBean,本文中以註解方式爲例:app








@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){   SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();   sqlSessionFactoryBean.setDataSource(dataSource);   return  sqlSessionFactoryBean;}


看一下SqlSessionFactoryBean的繼承實現關係:框架



先看spring中兩個很是重要的接口,FactoryBean和InitializingBean。ide


FactoryBean:ui

FactoryBean是一個spring中比較特殊的Bean,經過它的getObject()方法能夠返回一個對象實例。SqlSessionFactoryBean中getObject()方法的實現:spa



在這裏用於建立並返回一個SqlSessionFactory,在 spring +mybatis 的環境下,咱們使用SqlSessionFactoryBean來充當SqlSessionFactory。代理


InitializingBean:

InitializingBean接口中只有一個方法,afterPropertiesSet(),全部實現了接口的類,在bean的初始化以前都要調用這個方法。能夠看出在上面的getObject方法中,若是SqlSessionFactory爲空,會調用這個方法建立SqlSessionFactory


經過調用SqlSessionFactoryBuilder的build方法,最終返回了一個DefaultSqlSessionFactory實例,這個DefaultSqlSessionFactory中保存了一個很是重要的Configuration對象。


2、@MapperScan都作了什麼?


在註解配置mybatis時,經過@MapperScan指定Mapper存放的包,就能自動爲咱們把接口實現成類。那麼這是怎麼實現的呢?


點開@MapperScan的源碼,發現上面還有一行很是重要的註解:


@Import(MapperScannerRegistrar.class)



ImportBeanDefinitionRegistrar接口提供registerBeanDefinitions方法向用戶暴露了BeanDefinitionRegistry,也就是說可讓用戶手動建立BeanDefinition並使用該註冊器註冊到spring容器中。


查看MapperScannerRegistrar的方法registerBeanDefinitions中的核心代碼




ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);……scanner.doScan(StringUtils.toStringArray(basePackages));


主要是建立了一個Mapper掃描器,開啓掃描。

ClassPathMapperScanner中doScan方法:



這裏對生成的mapper的bean定義作了進一步處理

進入processBeanDefinitions()方法:



注意畫框代碼及上方的註釋,先看一下從BeanDefinitionHolder得到BeanDefinition時beanClass初始的值:



等待setBeanClass執行完畢:



經過definition.setBeanClass()把原來的BeanClass的類型替換成了MapperFactoryBean類型。到這,完成了Mapper接口加載定義階段中很是重要的一步,而這也是生成代理對象MapperProxy的關鍵。


3、mybatis如何生成代理對象?

看一下MapperFactoryBean的繼承關係:


圖片


MapperFactoryBean繼承的SqlSessionDaoSupport類實現了InitializingBean接口,那麼咱們仍是首先找afterPropertiesSet()方法:


圖片


DaoSupport中,最終調用MapperFactoryBean中的方法:


圖片


首先經過獲取sqlSession得到了很是重要的配置類Configuration,而後查看一下addMapper方法,最終調用的是MapperRegistry的addMapper方法:


圖片


紅框中的代碼爲咱們建立了Mapper 的代理工廠對象(還不是Mapper的代理對象),並把它放入了knownMappers這個Map中。


圖片


在這一步,只是簡單初始化了MapperProxyFactory,把咱們本身的mapper的類型傳給了它,還並無真正產生代理對象。


MapperRegistry並在以後的parse()方法中完成了xml文件的解析,每個sql方法都被解析成了一個MappedStatement對象,並添加到了配置類Configuration對象中。


MapperFactoryBean最終返回了什麼?

由於MapperFactoryBean實現了FactoryBean接口,因此咱們看看getObject方法究竟返回了什麼:



圖片


最終調用MapperRegistry的getMapper方法:


圖片


這裏調用的了mybatis剛纔生成的MapperProxyFactory,幫助咱們實例化並返回了一個代理對象。MapperProxyFactory中使用newInstance方法,實例化MapperProxy,用於生成代理


圖片


至此,咱們已經弄明白了文章開頭的MapperProxy是如何生成的。


4、MapperProxy代理對象如何執行sql語句?


在StudentServiceImpl中的query方法中打一個斷點跟蹤語句,你會發現實際執行的就是代理類MapperProxy中的invoke()方法。

圖片


MapperProxy在做爲代理類的同時,自身實現了InvocationHandler接口,因此invoke方法就是真正執行的代理邏輯。

圖片


在這裏最終調用了MapperMethod的execute方法實際去執行了sql語句。


圖片


在該方法中,根據sql語句執行類型,調用sqlSession對應的方法執行並將結果返回給用戶。至此,mybatis在spring環境下一次調用所有完成。

相關文章
相關標籤/搜索