MyBaits自动配置的魔法

摘要

MyBaits全自动配备的基本原理很简单,就是在创建SpringBoot工程项目时,导入mybatis-spring-boot-starter依赖。这个依赖实际上就是帮助我们导入了必要的mybatis依赖,非常方便实用。

正文

MyBaits全自动配备基本原理

序言

最先大家创建一个SpringBoot工程项目,导进mybatis-spring-boot-starter依靠。

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

导进后发觉这一依靠实际上便是协助大家导进了mybatis必须的依靠,在其中和全自动配备有关最重要的一个便是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全自动配备中是怎样工作中的

如上边剖析全自动配备的重要类大家就从mybatis-spring-boot-autoconfigure逐渐下手剖析。

QQ截图20210517172159.png

spring.factories

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

从spring.factories文档见到这儿根据SPI体制载入了2个类

  • MybatisAutoConfiguration
  • MybatisLanguateDriverAutoConfiguration.

MybatisAutoConfiguration

QQ截图20210517172514.png

//表明这是一个Spring配备类
@Configuration 
//这一类必须在classpath中存有SqlSessionFactory和SqlSessionFactoryBean时才起效
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) --
//这一类必须有一个DataSource的Canidate申请注册到Spring器皿中 
@ConditionalOnSingleCandidate(DataSource.class)
//使MybatisProperties注释类起效
@EnableConfigurationProperties({MybatisProperties.class})
//必须在DataSourceAutoConfiguration和MybatisLanguageDriverAutoConfiguration全自动配备以后实行
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
}

MybatisAutoConfiguration#sqlSessionFactory

@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
	//建立一个SqlSessionFactoryBean, 在mybatis-spring新项目下
    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()));
	}
    //运用Configuration目标
	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();
		}
	}

    //设定默认设置的语言表达驱动器类
	if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
		factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
	}
    //这儿默认设置会回到一个DefaultSqlSessionFactory目标
	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全自动配备实际上便是替大家完成了SqlSessionFactory和SqlSessionTempate的建立, 省掉了自身导进有关依靠和配备有关Bean的不便.

MybatisLanguageDriverAutoConfiguration

这一类的配备是对每个语言表达的适用,例如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包下,我删除了內部静态类下的编码,为了更好地维持这一类看上去更形象化

自定Mapper是怎样被扫描仪的

业务流程开发设计中,我们都是申明插口(Mapper),那麼大家自定的Mapper是怎样被扫描仪的呢, 大家再次沿着MybatisAutoConfiguration编码剖析,其內部包括了一个AutoConfiguredMapperScannerRegistrar的內部静态类.

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的基本包途径
			List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
            //2.转化成一个BeanDefinition的构造器,用以搭建MapperScannerConfigurer的                         //BeanDefinition
			BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
			builder.addPropertyValue("processPropertyPlaceHolders", true);
            //3.设定@Mapper注释的插口才会被当做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.这儿加上一个MapperScannerConfigurer的BeanDefinition目标,也就是引入一个
            //MapperScannerConfigurer目标
			registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
		}
	}

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

AutoConfiguredMapperScannerRegistrar类是MybatisAutoConfiguration的內部静态类,坐落于包org.mybatis.spring.boot.autoconfigure下。

能够见到这一类完成了ImportBeanDefinitionRegistrar插口,ImportBeanDefinitionRegistrar插口是Spring用于动态性申请注册Bean的,也就是会向Spring器皿中引入一个BeanDefinition, 这一BeanDefinition便是MapperScannerConfigurer。
ImportBeanDefinitionRegistrar完成类只有根据别的类@Import的方法来载入,一般是配备类或是运行类,因此MybatisAutoConfiguration类下还有一个内部类MapperScannerRegistrarNotFoundConfiguration以下。

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

这一方式 里最终会启用插口BeanDefinitionRegistry.registerBeanDefinition, beanName是”org.mybatis.spring.mapper.MapperScannerConfigurer”, registerBeanDefinition方式 具体会启用DefaultListableBeanFactory.registerBeanDefinition。DefaultListableBeanFactory是BeanDefinitionRegistry插口的完成类。
QQ截图20210518113732.png

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

}

AutoConfiguredMapperScannerRegistrar类和MapperScanner注释的功效是一样的,假如你沒有根据下列三种配备方法扫描仪Mapper插口的包途径

  • 配备MapperScannerConfigurer扫描枪种类的Spring Bean
  • @Mapper注释
  • <mybatis: scan/>标识

那麼这儿便会根据AutoConfiguredMapperScannerRegistrar类加上一个MapperScannerConfigurer扫描枪目标,去扫描仪SpringBoot包设定的基本包途径,也就是运行类的平级文件目录。 假如设定了@Mapper注释,则会当做Mapper插口分析,那麼这儿全自动配备则不起效。

MapperScannerConfigurer
QQ截图20210517175252.png

MapperScannerConfigurer

MapperScannerConfigurer完成了BeanDefinitionRegistryPostProcessor插口,BeanDefinitionRegistryPostProcessor 插口又承继了BeanFactoryPostProcessor插口, 换句话说在MapperScannerConfigurer类里必须完成这两个插口的方式 。

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

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

在MapperScannerConfigurer类里能够见到这儿只完成了postProcessBeanDefinitionRegistry。

QQ截图20210521091303.png

BeanDefinitionRegistryPostProcessor

Spring里有两个用于动态性申请注册Bean到器皿中(BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar)。ImportBeanDefinitionRegistrar上原文中有提及。
BeanDefinitionRegistryPostProcessor插口完成了BeanFactoryPostProcessor插口,是Spring架构的BeanDefinitionRegistry的后置摄像头CPU,用于申请注册附加的BeanDefinition,postProcessBeanDefinitionRegistry方式 会在全部的beanDefinition被载入了,可是全部的Bean还没有建立前启用。BeanDefinitionRegistryPostProcessor常常被用于申请注册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下.

这儿会启用ClassPathMapperScanner.scan(),而ClassPathMapperScanner又承继了ClassPathBeanDefinitionScanner,因此这儿scan()会启用ClassPathBeanDefinitionScanner.scan(), 而ClassPathBeanDefinitionScanner.scan() 第二句编码又启用了this.doScan(basePackages), this.doScan()又启用了ClassPathMapperScanner.doScan(), 而这一方式 第一句编码又启用了super.doScan(basePackages),父子俩类往返相互之间启用,有点儿晕头晕脑的。

org.mybatis.spring.mapper.ClassPathMapperScanner
org.springframework.context.annotation.ClassPathBeanDefinitionScanner这一类在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()
这一方式 里在mybatis全自动配备算较为关键的一个方式 ,也就是协助大家全自动配备MapperFactoryBean, 会把依据basePackage申请注册进Spring器皿的BeanDefinition的beanClass设成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 {
        //这是一个重要方式 ,会解决早已申请注册进Spring器皿的beanDefinition,也就是会把
        //早已申请注册进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];
        //这一方式 会扫描仪特定basePackage下被@Mapper注释标明的插口
        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, 初始值是类名首写小写字母
            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);
            }
            //查验相匹配的Mapper插口是不是被申请注册进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);
            }
        }
    }
    //这一结合回到之后 Spring器皿会将里边的全部內容申请注册到器皿中
    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.这儿把一般插口设成MapperFactoryBean
		definition.setBeanClass(this.mapperFactoryBeanClass);
        //2.是不是把Mapper插口添加到Mybatis的Config之中去, 这儿设定为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());
			}
		}
	}
}

QQ截图20210520174957.png

再看spring.factories文档

上边仅仅完成了MyBatis 全自动配备的工作中,那麼这种全自动配备是怎样在SpringBoot运作时实行呢? 你是否还记得SpringBoot的EnableAutoConfiguration注释吧,它是运用SpringFactoriesLoader体制载入全部的AutoConfiguration类,因此大家必须把撰写好的全自动配备类放到META-INF/spring.factories文档中,这也就是大家一开始剖析的mybatis-spring-boot-starter-autoconfigure的文档构造的缘故。

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

汇总

  1. mybatis-spring-boot-starter将mybatis必须的依靠所有引进。
  2. starter根据SPI体制引进了一个配备的Class(MyBatisAutoConfiguration)。它承担申请注册SqlSessionFactory和SqlSessionTemplate到Spring器皿中,应用MyBatis开发设计时绝大多数作用要应用这两个类来进行。
  3. 引入了AutoConfiguredMapperScannerRegistrar这一Bean到Spring器皿,它承担将MapperScanner引进到Spring器皿,随后MapperScanner会将工程项目中特定package下的Mapper转换为BeanDefinition而且申请注册到Spring器皿中。
  4. 在开发设计中应用某一实际的Mapper时,Spring可以从器皿中寻找这一Mapper相匹配的BeanDefinition,将其创建对象而且引入,那样开发人员就可以应用了。
  5. SpringBoot MyBatis全自动配备牵涉到Spring中2个全自动申请注册Bean的重要插口(BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar),也是大家业务流程开发设计中必须重点关注的地区。

参照连接

https://www.cnblogs.com/nullifier/p/11967659.html
https://zhuanlan.zhihu.com/p/30123517
https://www.cnblogs.com/daxin/p/3545040.html

关注不迷路

扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!

温馨提示:如果您访问和下载本站资源,表示您已同意只将下载文件用于研究、学习而非其他用途。
文章版权声明 1、本网站名称:宇凡盒子
2、本站文章未经许可,禁止转载!
3、如果文章内容介绍中无特别注明,本网站压缩包解压需要密码统一是:yufanbox.com
4、本站仅供资源信息交流学习,不保证资源的可用及完整性,不提供安装使用及技术服务。点此了解
5、如果您发现本站分享的资源侵犯了您的权益,请及时通知我们,我们会在接到通知后及时处理!提交入口
0

评论0

请先

站点公告

🚀 【宇凡盒子】全网资源库转储中心

👉 注册即送VIP权限👈

👻 全站资源免费下载✅,欢迎注册!

记得 【收藏】+【关注】 谢谢!~~~

立即注册
没有账号?注册  忘记密码?

社交账号快速登录