摘要
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逐渐下手剖析。
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
//表明这是一个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插口的完成类。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory,
BeanDefinitionRegistry,
Serializable {
}
AutoConfiguredMapperScannerRegistrar类和MapperScanner注释的功效是一样的,假如你沒有根据下列三种配备方法扫描仪Mapper插口的包途径
- 配备MapperScannerConfigurer扫描枪种类的Spring Bean
- @Mapper注释
- <mybatis: scan/>标识
那麼这儿便会根据AutoConfiguredMapperScannerRegistrar类加上一个MapperScannerConfigurer扫描枪目标,去扫描仪SpringBoot包设定的基本包途径,也就是运行类的平级文件目录。 假如设定了@Mapper注释,则会当做Mapper插口分析,那麼这儿全自动配备则不起效。
MapperScannerConfigurer
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。
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());
}
}
}
}
再看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
汇总
- mybatis-spring-boot-starter将mybatis必须的依靠所有引进。
- starter根据SPI体制引进了一个配备的Class(MyBatisAutoConfiguration)。它承担申请注册SqlSessionFactory和SqlSessionTemplate到Spring器皿中,应用MyBatis开发设计时绝大多数作用要应用这两个类来进行。
- 引入了AutoConfiguredMapperScannerRegistrar这一Bean到Spring器皿,它承担将MapperScanner引进到Spring器皿,随后MapperScanner会将工程项目中特定package下的Mapper转换为BeanDefinition而且申请注册到Spring器皿中。
- 在开发设计中应用某一实际的Mapper时,Spring可以从器皿中寻找这一Mapper相匹配的BeanDefinition,将其创建对象而且引入,那样开发人员就可以应用了。
- 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
关注不迷路
扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!
评论0