欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring和Mybatis整合的原理詳解

 更新時(shí)間:2022年07月05日 14:44:22   作者:??江粒??  
這篇文章主要介紹了Spring和Mybatis整合的原理詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言

最近讀完了Spring的IOC部分的源碼,受益匪淺,這篇文章講解一下MyBatis是如何做到與Spring整合的。MyBatis是如何做到干擾Spring的生命周期,把Mapper一個(gè)個(gè)的注冊到Spring容器中的將在這里揭秘。

簡單猜想

因?yàn)殚喿x過Spring源碼后對他有了一定的認(rèn)識,這里可以簡單盲猜一下,使用的是什么方式,在上一篇文章揭秘Autowired注解中有介紹到。我們只是向xml中寫入了一行<context:annotation-config/>配置。Spring就像BeanFatory中寫入了很多的BeanPostProcessor,這里我覺得采用的功能類似。
通過定義spring.handlers文件。然后mybatis定義各種處理標(biāo)簽的Handler和Paser。隨后通過讀取配置文件中的mappers標(biāo)簽,去像register中注冊BeanDefinition,這是其一。

第二種方法就是類似AutowiredAnnotationBeanPostProcessor的實(shí)現(xiàn)方式,通過Xml注冊一個(gè)Bean,這個(gè)Bean繼承自MergedBeanDefinitionPostProcessor,由于繼承自MegedBeanDefinitionPostProcessor所以他會優(yōu)先Bean運(yùn)行,在此時(shí)可以像Bean工廠中添加BeanDefinition。

其實(shí)我們的目標(biāo)很明確,只要我們能在Spring調(diào)用InitiazionBean方法之前去把mapper的BeanDefinition添加進(jìn)Spring容器,都可以實(shí)現(xiàn)當(dāng)前的目的。

那么接下來我們就看看MyBatis本身究竟是如何實(shí)現(xiàn)的吧。

案例搭建

源碼地址:MyBatis整合Spring有兩種方式,第一種是通過Xml,第二種是通過Mapper接口的掃描,具體的整合方法我這里就不演示了,直接看配置文件吧。其實(shí)就是application.xml有一點(diǎn)改動。

通過掃描接口

這里搭建一個(gè)最簡單的整合方式:

正式開始

通過上方的配置文件,可以看見一個(gè)配置了一個(gè)叫scannerConfigurer,這里先去看一下這個(gè)類。

public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

這個(gè)類繼承了幾個(gè)接口:

  • BeanDefinitionRegistryPostProcessor
  • 這個(gè)接口追進(jìn)去,發(fā)現(xiàn)該接口繼承自BeanFactoryPostProcessor,也就相當(dāng)于spring在refresh方法中有一個(gè)方法專門去執(zhí)行這類的接口。
  • InitializingBean
  • 在createBean的生命周期中會調(diào)用該接口的afterProperties方法。
  • ApplicationContextAware
  • Spring在創(chuàng)建該Bean時(shí)會調(diào)用setapplicationContext方法注入上下文
  • BeanNameAware
  • 創(chuàng)建是調(diào)用setBeanName方法

按照這樣的一個(gè)接口被執(zhí)行的順序是,setBeanName -> setApplicationContext -> afterproperties -> postProcessBeanDefinitionRegistry

setBeanName

@Override
public void setBeanName(String name) {
  this.beanName = name;
}

這個(gè)方法很明顯不是。

setApplicationContext

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
  this.applicationContext = applicationContext;
}

這個(gè)方法很明顯,也不是。

afterProperties

@Override
public void afterPropertiesSet() throws Exception {
  notNull(this.basePackage, "Property 'basePackage' is required");
}

這個(gè)方法是用來校驗(yàn)的,判斷了basePackage是否為空,如果為空就throw Exception。

postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  if (this.processPropertyPlaceHolders) {
    processPropertyPlaceHolders();
  }

  ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  scanner.setAddToConfig(this.addToConfig);
  scanner.setAnnotationClass(this.annotationClass);
  scanner.setMarkerInterface(this.markerInterface);
  scanner.setSqlSessionFactory(this.sqlSessionFactory);
  scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
  scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
  scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
  scanner.setResourceLoader(this.applicationContext);
  scanner.setBeanNameGenerator(this.nameGenerator);
  scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
  if (StringUtils.hasText(lazyInitialization)) {
    scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
  }
  if (StringUtils.hasText(defaultScope)) {
    scanner.setDefaultScope(defaultScope);
  }
  scanner.registerFilters();
  scanner.scan(
      StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

那這里就很明顯了,這里創(chuàng)建ClassPathMapperScanner。隨后對scanner的一些配置做了一些設(shè)置。

然后就調(diào)用了registerFilters方法,字面意思也就是注冊過濾器,這里就跳過吧,無非是設(shè)置一些屬性,然后在后面解析的時(shí)候判斷過濾條件,在循環(huán)時(shí)continue。

主要是scan方法這里要詳細(xì)看一下:

public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    this.doScan(basePackages);
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}

這里這個(gè)掃描類其實(shí)是Spring中的類,ClassPathBeanDefinitionScanner,當(dāng)中的scan方法。所以這里可能會有點(diǎn)眼熟,類似于創(chuàng)建Bean時(shí),先獲取一下創(chuàng)建之前的Bean總數(shù),然后再獲取創(chuàng)建之后的Bean總數(shù),返回時(shí)減一下就知道這次創(chuàng)建了多少。

總結(jié)

其實(shí)到這里呢,我們就算是結(jié)束了,因?yàn)楹罄m(xù)的包掃描,在嚴(yán)格意義上來講是Spring來實(shí)現(xiàn)的,我后續(xù)開篇文章來講解這個(gè)東西。

這里總結(jié)一下,正如我猜想的一樣,myBatis只要在finishBeanFactoryInitialization方法之前,把Mapper的BeanDefinition塞進(jìn)Spring容器中,在最后的finishBeanFactoryInitialization方法,Spring自然就會根據(jù)BeanDefinition去創(chuàng)建Bean了。

這里使用的方法是,注冊一個(gè)BeanFactoryPostProcessor,所以這個(gè)方法會在finishBeanFactoryInitialization方法之前運(yùn)行,所以這里是成功的。

到此這篇關(guān)于Spring和Mybatis整合的原理詳解的文章就介紹到這了,更多相關(guān)Spring和Mybatis整合內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論