<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          MyBaits自動(dòng)配置原理

          共 31035字,需瀏覽 63分鐘

           ·

          2021-05-28 11:00

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

            作者 |  歪頭兒在帝都

          來源 |  urlify.cn/j2MfQj

          前言

          首先我們建立一個(gè)SpringBoot工程,導(dǎo)入mybatis-spring-boot-starter依賴。

          <dependency>
              <groupId>org.mybatis.spring.boot</groupId>
              <artifactId>mybatis-spring-boot-starter</artifactId>
              <version>2.1.4</version>
          </dependency>

          導(dǎo)入后發(fā)現(xiàn)這個(gè)依賴其實(shí)就是幫助我們導(dǎo)入了mybatis需要的依賴,其中和自動(dòng)配置相關(guān)最重要的一個(gè)就是mybatis-spring-boot-autoconfigure

          <dependencies>
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
              </dependency>
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
              </dependency>
              <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
              </dependency>
              <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
              </dependency>
              <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
              </dependency>
            </dependencies>

          MyBatis自動(dòng)配置中是如何工作的

          如上面分析自動(dòng)配置的關(guān)鍵類我們就從mybatis-spring-boot-autoconfigure開始著手分析。

          spring.factories

          # Auto Configure
          org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
          org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
          org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

          從spring.factories文件看到這里通過SPI機(jī)制加載了兩個(gè)類

          • MybatisAutoConfiguration

          • MybatisLanguateDriverAutoConfiguration.

          MybatisAutoConfiguration

          //表示這是一個(gè)Spring配置類
          @Configuration 
          //這個(gè)類需要在classpath中存在SqlSessionFactory和SqlSessionFactoryBean時(shí)才生效
          @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) --
          //這個(gè)類需要有一個(gè)DataSource的Canidate注冊(cè)到Spring容器中 
          @ConditionalOnSingleCandidate(DataSource.class)
          //使MybatisProperties注解類生效
          @EnableConfigurationProperties({MybatisProperties.class})
          //需要在DataSourceAutoConfiguration和MybatisLanguageDriverAutoConfiguration自動(dòng)配置之后執(zhí)行
          @AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
          public class MybatisAutoConfiguration implements InitializingBean {
             
          }

          MybatisAutoConfiguration#sqlSessionFactory

          @Bean
          @ConditionalOnMissingBean
          public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
           //創(chuàng)建一個(gè)SqlSessionFactoryBean, 在mybatis-spring項(xiàng)目下
              SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
           factory.setDataSource(dataSource);
           factory.setVfs(SpringBootVFS.class);
           if (StringUtils.hasText(this.properties.getConfigLocation())) {
                 factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
           }
              
              //應(yīng)用Configuration對(duì)象
           this.applyConfiguration(factory);
           if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
           }

           if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
           }

           if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
           }

           if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
           }

           if (this.properties.getTypeAliasesSuperType() != null) {
            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
           }

           if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
           }

           if (!ObjectUtils.isEmpty(this.typeHandlers)) {
            factory.setTypeHandlers(this.typeHandlers);
           }

           if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
           }

           Set<String> factoryPropertyNames = (Set)Stream.of((new BeanWrapperImpl(SqlSessionFactoryBean.class)).getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
           Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
           if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
            factory.setScriptingLanguageDrivers(this.languageDrivers);
            if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
             defaultLanguageDriver = this.languageDrivers[0].getClass();
            }
           }

              //設(shè)置默認(rèn)的語言驅(qū)動(dòng)類
           if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
            factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
           }
            
              //這里默認(rèn)會(huì)返回一個(gè)DefaultSqlSessionFactory對(duì)象
           return factory.getObject();
          }

          MybatisAutoConfiguration#sqlSessionTemplate

          @Bean
          @ConditionalOnMissingBean
          public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
           ExecutorType executorType = this.properties.getExecutorType();
           return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
          }

          到這里也就知道了MyBatis自動(dòng)配置其實(shí)就是替我們完成了SqlSessionFactory和SqlSessionTempate的創(chuàng)建, 省去了自己導(dǎo)入相關(guān)依賴和配置相關(guān)Bean的麻煩.

          MybatisLanguageDriverAutoConfiguration

          這個(gè)類的配置是對(duì)各個(gè)語言的支持,比如Thymeleaf, Velocity,LegacyVelociy, FreeMarker等視圖組件的支持。

          @Configuration
          @ConditionalOnClass({LanguageDriver.class})
          public class MybatisLanguageDriverAutoConfiguration {
              private static final String CONFIGURATION_PROPERTY_PREFIX = "mybatis.scripting-language-driver";

              public MybatisLanguageDriverAutoConfiguration() {
              }

              @Configuration
              @ConditionalOnClass({ThymeleafLanguageDriver.class})
              public static class ThymeleafConfiguration {
                  public ThymeleafConfiguration() {
                  }
              }

              @Configuration
              @ConditionalOnClass({VelocityLanguageDriver.class, VelocityLanguageDriverConfig.class})
              public static class VelocityConfiguration {
                  public VelocityConfiguration() {
                  }
              }

              @Configuration
              @ConditionalOnClass({Driver.class})
                   @ConditionalOnMissingClass({"org.mybatis.scripting.velocity.VelocityLanguageDriverConfig"})
              public static class LegacyVelocityConfiguration {
                  public LegacyVelocityConfiguration() {
                  }
              }

              @Configuration
              @ConditionalOnClass({FreeMarkerLanguageDriver.class, FreeMarkerLanguageDriverConfig.class})
              public static class FreeMarkerConfiguration {
                  public FreeMarkerConfiguration() {
                  }
              }

              @Configuration
              @ConditionalOnClass({FreeMarkerLanguageDriver.class})
              @ConditionalOnMissingClass({"org.mybatis.scripting.freemarker.FreeMarkerLanguageDriverConfig"})
              public static class LegacyFreeMarkerConfiguration {
                  public LegacyFreeMarkerConfiguration() {
                  }
              }
          }

          MybatisLanguageDriverAutoConfiguration類在org.mybatis.spring.boot.autoconfigure包下,我刪掉了內(nèi)部靜態(tài)類下的代碼,為了保持這個(gè)類看起來更直觀

          自定義Mapper是如何被掃描的

          業(yè)務(wù)開發(fā)中,我們是聲明接口(Mapper),那么我們自定義的Mapper是如何被掃描的呢, 我們繼續(xù)順著MybatisAutoConfiguration代碼分析,其內(nèi)部包含了一個(gè)AutoConfiguredMapperScannerRegistrar的內(nèi)部靜態(tài)類.

          AutoConfiguredMapperScannerRegistrar

          registerBeanDefinitions

          public static class AutoConfiguredMapperScannerRegistrar 
              implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
           private BeanFactory beanFactory;

           public AutoConfiguredMapperScannerRegistrar() {
           }

           public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (!AutoConfigurationPackages.has(this.beanFactory)) {
             
            } else {
                   //1.獲取到SpringBoot的基礎(chǔ)包路徑
             List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
             
                      //2.生成一個(gè)BeanDefinition的構(gòu)造器,用于構(gòu)建MapperScannerConfigurer的                         //BeanDefinition
             BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
             builder.addPropertyValue("processPropertyPlaceHolders"true);
                      //3.設(shè)置@Mapper注解的接口才會(huì)被當(dāng)成Mapper接口
             builder.addPropertyValue("annotationClass", Mapper.class);
                      
             builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
             BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
             //4.獲取MapperScannerConfigurer的屬性名稱
                      Set<String> propertyNames = (Set)Stream.of(beanWrapper.getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
             if (propertyNames.contains("lazyInitialization")) {
              builder.addPropertyValue("lazyInitialization""${mybatis.lazy-initialization:false}");
             }

             if (propertyNames.contains("defaultScope")) {
              builder.addPropertyValue("defaultScope""${mybatis.mapper-default-scope:}");
             }
                      //5.這里添加一個(gè)MapperScannerConfigurer的BeanDefinition對(duì)象,也就是注入一個(gè)
                      //MapperScannerConfigurer對(duì)象
             registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
            }
           }

           public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
           }
          }

          AutoConfiguredMapperScannerRegistrar類是MybatisAutoConfiguration的內(nèi)部靜態(tài)類,位于包org.mybatis.spring.boot.autoconfigure下。

          可以看到這個(gè)類實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar接口是Spring用來動(dòng)態(tài)注冊(cè)Bean的,也就是會(huì)向Spring容器中注入一個(gè)BeanDefinition, 這個(gè)BeanDefinition就是MapperScannerConfigurer。
          ImportBeanDefinitionRegistrar實(shí)現(xiàn)類只能通過其他類@Import的方式來加載,通常是配置類或者啟動(dòng)類,所以MybatisAutoConfiguration類下還有一個(gè)內(nèi)部類MapperScannerRegistrarNotFoundConfiguration如下。

          @Configuration
          @Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
          @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
          public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
                  
          }

          這個(gè)方法里最后會(huì)調(diào)用接口BeanDefinitionRegistry.registerBeanDefinition, beanName是"org.mybatis.spring.mapper.MapperScannerConfigurer", registerBeanDefinition方法實(shí)際會(huì)調(diào)用DefaultListableBeanFactory.registerBeanDefinition。DefaultListableBeanFactory是BeanDefinitionRegistry接口的實(shí)現(xiàn)類。

          public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory 
              implements ConfigurableListableBeanFactory, 
                         BeanDefinitionRegistry, 
                         Serializable {

          }

          AutoConfiguredMapperScannerRegistrar類和MapperScanner注解的作用是一樣的,如果你沒有通過以下三種配置方式掃描Mapper接口的包路徑

          • 配置MapperScannerConfigurer掃描器類型的Spring Bean

          • @Mapper注解

          • <mybatis: scan/>標(biāo)簽

          那么這里就會(huì)通過AutoConfiguredMapperScannerRegistrar類添加一個(gè)MapperScannerConfigurer掃描器對(duì)象,去掃描SpringBoot包設(shè)置的基礎(chǔ)包路徑,也就是啟動(dòng)類的同級(jí)目錄。如果設(shè)置了@Mapper注解,則會(huì)當(dāng)成Mapper接口解析,那么這里自動(dòng)配置則不生效。

          MapperScannerConfigurer

          MapperScannerConfigurer

          MapperScannerConfigurer實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor 接口又繼承了BeanFactoryPostProcessor接口, 也就是說在MapperScannerConfigurer類里需要實(shí)現(xiàn)這兩個(gè)接口的方法。

          public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
              void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
          }

          @FunctionalInterface
          public interface BeanFactoryPostProcessor {
              void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
          }

          在MapperScannerConfigurer類里可以看到這里只實(shí)現(xiàn)了postProcessBeanDefinitionRegistry。

          BeanDefinitionRegistryPostProcessor

          Spring里有兩個(gè)用來動(dòng)態(tài)注冊(cè)Bean到容器中(BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar)。ImportBeanDefinitionRegistrar上文中有提到。
          BeanDefinitionRegistryPostProcessor接口實(shí)現(xiàn)了BeanFactoryPostProcessor接口,是Spring框架的BeanDefinitionRegistry的后置處理器,用來注冊(cè)額外的BeanDefinition,postProcessBeanDefinitionRegistry方法會(huì)在所有的beanDefinition被加載了,但是所有的Bean還沒創(chuàng)建前調(diào)用。BeanDefinitionRegistryPostProcessor經(jīng)常被用來注冊(cè)BeanFactoryPostProcessor的BeanDefinition。


          postProcessBeanDefinitionRegistry

          public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
              
              public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
                  if (this.processPropertyPlaceHolders) {
                      this.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(this.lazyInitialization)) {
                      scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
                  }

                  if (StringUtils.hasText(this.defaultScope)) {
                      scanner.setDefaultScope(this.defaultScope);
                  }

                  scanner.registerFilters();
                  scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
              }
          }

          MapperScannerConfigurer在包org.mybatis.spring.mapper下.


          這里會(huì)調(diào)用ClassPathMapperScanner.scan(),而ClassPathMapperScanner又繼承了ClassPathBeanDefinitionScanner,所以這里scan()會(huì)調(diào)用ClassPathBeanDefinitionScanner.scan(), 而ClassPathBeanDefinitionScanner.scan() 第二句代碼又調(diào)用了this.doScan(basePackages), this.doScan()又調(diào)用了ClassPathMapperScanner.doScan(), 而這個(gè)方法第一句代碼又調(diào)用了super.doScan(basePackages),父子類來回互相調(diào)用,有點(diǎn)暈頭轉(zhuǎn)向的。

          org.mybatis.spring.mapper.ClassPathMapperScanner
          org.springframework.context.annotation.ClassPathBeanDefinitionScanner這個(gè)類在spring-context.jar


          ClassPathMapperScanner

          ClassPathBeanDefinitionScanner#scan

          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;
          }

          ClassPathMapperScanner#doScan()
          這個(gè)方法里在mybatis自動(dòng)配置算比較重要的一個(gè)方法,也就是幫助我們自動(dòng)配置MapperFactoryBean, 會(huì)把根據(jù)basePackage注冊(cè)進(jìn)Spring容器的BeanDefinition的beanClass設(shè)置成MapperFactoryBean。

          public Set<BeanDefinitionHolder> doScan(String... basePackages) {
              Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
              if (beanDefinitions.isEmpty()) {
                  LOGGER.warn(() -> {
                      return "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.";
                  });
              } else {
                  //這是一個(gè)關(guān)鍵方法,會(huì)處理已經(jīng)注冊(cè)進(jìn)Spring容器的beanDefinition,也就是會(huì)把
                  //已經(jīng)注冊(cè)進(jìn)Spring容器的beanDefinitiond的beanClass為MapperFactoryBean
                  this.processBeanDefinitions(beanDefinitions);
              }

              return beanDefinitions;
          }

          ClassPathBeanDefinitionScanner#doScan()

          protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
              Assert.notEmpty(basePackages, "At least one base package must be specified");
              Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
              String[] var3 = basePackages;
              int var4 = basePackages.length;
              
              for(int var5 = 0; var5 < var4; ++var5) {
                  String basePackage = var3[var5];
                  //這個(gè)方法會(huì)掃描指定basePackage下被@Mapper注解標(biāo)注的接口
                  Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
                  Iterator var8 = candidates.iterator();

                  while(var8.hasNext()) {
                      BeanDefinition candidate = (BeanDefinition)var8.next();
                      ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                      candidate.setScope(scopeMetadata.getScopeName());
                      //這里獲取beanName, 默認(rèn)值是類名首字母小寫
                      String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                      if (candidate instanceof AbstractBeanDefinition) {
                          this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
                      }

                      if (candidate instanceof AnnotatedBeanDefinition) {
                          AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
                      }
                      //檢查對(duì)應(yīng)的Mapper接口是否被注冊(cè)進(jìn)Spring容器中。
                      if (this.checkCandidate(beanName, candidate)) {
                          BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                          definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                          beanDefinitions.add(definitionHolder);
                          this.registerBeanDefinition(definitionHolder, this.registry);
                      }
                  }
              }
              
              //這個(gè)集合返回以后 Spring容器會(huì)將里面的所有內(nèi)容注冊(cè)到容器中
              return beanDefinitions;
          }

          ClassPathMapperScanner#processBeanDefinitions

          private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
           BeanDefinitionRegistry registry = this.getRegistry();
           Iterator var4 = beanDefinitions.iterator();

           while(var4.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var4.next();
            AbstractBeanDefinition definition = (AbstractBeanDefinition)holder.getBeanDefinition();
            boolean scopedProxy = false;
            if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
             definition = (AbstractBeanDefinition)Optional.ofNullable(((RootBeanDefinition)definition).getDecoratedDefinition()).map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> {
              return new IllegalStateException("The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]");
             });
             scopedProxy = true;
            }

            String beanClassName = definition.getBeanClassName();
            LOGGER.debug(() -> {
             return "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface";
            });
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
            //1.這里把普通接口設(shè)置成MapperFactoryBean
            definition.setBeanClass(this.mapperFactoryBeanClass);
                  //2.是否把Mapper接口加入到Mybatis的Config當(dāng)中去, 這里設(shè)置為true
            definition.getPropertyValues().add("addToConfig", this.addToConfig);
            definition.setAttribute("factoryBeanObjectType", beanClassName);
            boolean explicitFactoryUsed = false;
            
            //2.從核心容器里獲取SqlSessionFactory賦值給MapperFactoryBean
            if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
             definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
             explicitFactoryUsed = true;
            } else if (this.sqlSessionFactory != null) {
             definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
             explicitFactoryUsed = true;
            }
            
            //3.從核心容器里獲取SqlSessionTemplate賦值給MapperFactoryBean
            if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
             if (explicitFactoryUsed) {
              LOGGER.warn(() -> {
               return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.";
              });
             }

             definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
             explicitFactoryUsed = true;
            } else if (this.sqlSessionTemplate != null) {
             if (explicitFactoryUsed) {
              LOGGER.warn(() -> {
               return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.";
              });
             }

             definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
             explicitFactoryUsed = true;
            }

            if (!explicitFactoryUsed) {
             LOGGER.debug(() -> {
              return "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.";
             });
             definition.setAutowireMode(2);
            }

            definition.setLazyInit(this.lazyInitialization);
            if (!scopedProxy) {
             if ("singleton".equals(definition.getScope()) && this.defaultScope != null) {
              definition.setScope(this.defaultScope);
             }

             if (!definition.isSingleton()) {
              BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
              if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
               registry.removeBeanDefinition(proxyHolder.getBeanName());
              }

              registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
             }
            }
           }
          }


          再看spring.factories文件

          上面只是完成了MyBatis 自動(dòng)配置的工作,那么這些自動(dòng)配置是如何在SpringBoot啟動(dòng)時(shí)執(zhí)行呢?還記得SpringBoot的EnableAutoConfiguration注解吧,它是利用SpringFactoriesLoader機(jī)制加載所有的AutoConfiguration類,所以我們需要把編寫好的自動(dòng)配置類放在META-INF/spring.factories文件中,這也就是我們一開始分析的mybatis-spring-boot-starter-autoconfigure的文件結(jié)構(gòu)的原因。

          # Auto Configure
          org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
          org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
          org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration


          總結(jié)

          1. mybatis-spring-boot-starter將mybatis需要的依賴全部引入。

          2. starter通過SPI機(jī)制引入了一個(gè)配置的Class(MyBatisAutoConfiguration)。它負(fù)責(zé)注冊(cè)SqlSessionFactory和SqlSessionTemplate到Spring容器中,使用MyBatis開發(fā)時(shí)絕大部分功能要使用這兩個(gè)類來完成。

          3. 注入了AutoConfiguredMapperScannerRegistrar這個(gè)Bean到Spring容器,它負(fù)責(zé)將MapperScanner引入到Spring容器,然后MapperScanner會(huì)將工程中指定package下的Mapper轉(zhuǎn)化為BeanDefinition并且注冊(cè)到Spring容器中。

          4. 在開發(fā)中使用某個(gè)具體的Mapper時(shí),Spring能夠從容器中找到這個(gè)Mapper對(duì)應(yīng)的BeanDefinition,將其實(shí)例化并且注入,這樣開發(fā)者就可以使用了。

          5. SpringBoot+MyBatis自動(dòng)配置涉及到Spring中兩個(gè)自動(dòng)注冊(cè)Bean的關(guān)鍵接口(BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar),也是我們業(yè)務(wù)開發(fā)中需要重點(diǎn)關(guān)注的地方。






          粉絲福利:Java從入門到入土學(xué)習(xí)路線圖

          ??????

          ??長(zhǎng)按上方微信二維碼 2 秒


          感謝點(diǎn)贊支持下哈 

          瀏覽 120
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  h文在线播放 | 黄色成人在线看 | 丁香人人六月综合查询 | 欧美色色爱爱男人天堂 | 一区二区三区四区精品无码 |