后面咱们摸清楚了整个invokeBeanFactoryPostProcessors办法的if-else逻辑和3个for循环的外围脉络逻辑。

接下来咱们来看下细节,我会通过抓大放小的思维,带大家看到在扩大点执行的过程中,最最要的有哪一些。

SpringBoot的主动拆卸配置如何做到的、第三方技术如何进行扩大的。

SpringBoot的主动拆卸配置如何做到的?

if-else逻辑中哪些BeanFactoryPostProcessor执行了?

之前咱们提到过,invokeBeanFactoryPostProcessors执行的BeanFactoryPostProcessor次要起源是容器的两个属性
beanFactoryPostProcessorsBeanDefinitionMap

首先这两个属性,会在之前执行扩大操作,比方listener或者initializer的办法时,设置进去值的。执行到invokeBeanFactoryPostProcessors时,之前会设置如下图所示的值:

从上图能够看进去,执行invokeBeanFactoryPostProcessors的时候曾经有4个BeanFactoryPostProcessor。

当执行invokeBeanFactoryPostProcessors,外围脉络上一节咱们剖析出了是次要一个if-else+3个for循环组成的,这个if-else中有分了外部的、实现PriorityOrderd、Ordered、NonOrder这个四个程序执行。联合下面4个BeanFactoryPostProcessor,整体执行如下图所示:

从图中能够看进去,十分要害的一点那就是:在执行扩大办法1的过程中,通过Spring外部的一个ConfigurationClassPostProcessor,补充了新的BeanDefinition,减少了新的BeanFactoryPostProcessor。

ConfigurationClassPostProcessor这个执行十分要害,因为它补充了新的BeanDefinition。

它外围用来进行加载ClassPath下所有java注解定义的BeanDefinition。比方:本人包下定义的@Service,@Component,@Controller@Configuration @Bean等注解定义的Bean,也包含内部的starter中@Configuration @Bean等配置。

也就是你定义的大多数bean和内部starter定义的Bean的BeanDefinition都会被放入到容器中。

另外,补充了新的BeanDefinition,这里咱们简化了下,假如以后利用,只依赖了一个myBatis-starter,之后只会补充一个MyBatis相干的BeanDefinition,一个BeanFactoryPostProcessor—MapperScannerConfigurer。从名字上猜想,它应该是用来扫描MyBatis相干bean的。

invokeBeanFactoryPostProcessors的if-else逻辑中,触发了2个扩大操作,最初还会执行扩大办法2,之前的所有BeanFactoryPostProcessor,对立会执行扩大办法2。

扩大办法2执行的逻辑,根本没有什么外围的,这里咱们就间接过了,你晓得invokeBeanFactoryPostProcessors这里会触发这个扩大点,并且在扩大办法1之后执行就行了。

最终执行完if-else后,BeanFactory中的次要有如下的beanDefination:

beanDefinitionNames = {ArrayList@3752}  size = 164 0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor" 1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor" 2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor" 3 = "org.springframework.context.event.internalEventListenerProcessor" 4 = "org.springframework.context.event.internalEventListenerFactory" 5 = "learnSpringBootApplication" 6 = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory" 7 = "userController" 8 = "myBeanPostProcessor" 9 = "userServiceImpl" 10 = "userMapper" 11 = "org.springframework.boot.autoconfigure.AutoConfigurationPackages" 12 = "org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration" 13 = "propertySourcesPlaceholderConfigurer" 14 = "org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration" 15 = "websocketServletWebServerCustomizer" 16 = "org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration" 17 = "org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat" 18 = "tomcatServletWebServerFactory" 19 = "org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration" 20 = "servletWebServerFactoryCustomizer" 21 = "tomcatServletWebServerFactoryCustomizer" 22 = "org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor" 23 = "org.springframework.boot.context.internalConfigurationPropertiesBinderFactory" 24 = "org.springframework.boot.context.internalConfigurationPropertiesBinder" 25 = "org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator" 26 = "org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata" 27 = "server-org.springframework.boot.autoconfigure.web.ServerProperties" 28 = "webServerFactoryCustomizerBeanPostProcessor" 29 = "errorPageRegistrarBeanPostProcessor" 30 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletConfiguration" 31 = "dispatcherServlet" 32 = "spring.mvc-org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties" 33 = "spring.http-org.springframework.boot.autoconfigure.http.HttpProperties" 34 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration" 35 = "dispatcherServletRegistration" 36 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration" 37 = "org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration" 38 = "taskExecutorBuilder" 39 = "applicationTaskExecutor" 40 = "spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties" 41 = "org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration" 42 = "defaultValidator" 43 = "methodValidationPostProcessor" 44 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration" 45 = "error" 46 = "beanNameViewResolver" 47 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$DefaultErrorViewResolverConfiguration" 48 = "conventionErrorViewResolver" 49 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration" 50 = "errorAttributes" 51 = "basicErrorController" 52 = "errorPageCustomizer" 53 = "preserveErrorControllerTargetClassPostProcessor" 54 = "spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties" 55 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration" 56 = "requestMappingHandlerAdapter" 57 = "requestMappingHandlerMapping" 58 = "welcomePageHandlerMapping" 59 = "mvcConversionService" 60 = "mvcValidator" 61 = "mvcContentNegotiationManager" 62 = "mvcPathMatcher" 63 = "mvcUrlPathHelper" 64 = "viewControllerHandlerMapping" 65 = "beanNameHandlerMapping" 66 = "routerFunctionMapping" 67 = "resourceHandlerMapping" 68 = "mvcResourceUrlProvider" 69 = "defaultServletHandlerMapping" 70 = "handlerFunctionAdapter" 71 = "mvcUriComponentsContributor" 72 = "httpRequestHandlerAdapter" 73 = "simpleControllerHandlerAdapter" 74 = "handlerExceptionResolver" 75 = "mvcViewResolver" 76 = "mvcHandlerMappingIntrospector" 77 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter" 78 = "defaultViewResolver" 79 = "viewResolver" 80 = "requestContextFilter" 81 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration" 82 = "formContentFilter" 83 = "org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari" 84 = "dataSource" 85 = "org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration$Hikari" 86 = "org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration" 87 = "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$PooledDataSourceConfiguration" 88 = "org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration" 89 = "hikariPoolDataSourceMetadataProvider" 90 = "org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration" 91 = "org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker" 92 = "org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationConfiguration" 93 = "dataSourceInitializerPostProcessor" 94 = "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration" 95 = "spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties" 96 = "com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration" 97 = "sqlSessionFactory" 98 = "sqlSessionTemplate" 99 = "mybatis-plus-com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties"

SpringBoot的主动拆卸配置理论是通过starter+@Conditional注解+@Import注解+invokeBeanFactoryPostProcessors触发扩大点独特实现的。

下面每个点都有一些比拟有意思的设计。

这句话你第一次听必定不了解,没关系,等我讲完这这一节你就会明确SpringBoot外围装配置的的几个设计点了。

既然从容器中获取到之前放入的对象ConfigurationClassPostProcessor这个对象十分外围,用来减少BeanDefination的。

接下来,咱们就来详细分析下它的外围原理,看看它是如何减少BeanDefination的,并且扫描出内部的starter的。

术语遍及starter是什么?

starter是SpringBoot定义的曾经有一些默认javaConfig配置好类,通过封装成jar,定义好maven的依赖,为咱们提供了便当的配置起步依赖。

也就是说,咱们能够定义了常见的Spring和第三方技术整合的默认配置,或者咱们本人定义默认的整合第三方技术或者自研技术的配置,这样的性能是十分便当的。

在下面咱们提到了invokeBeanFactoryPostProcessors中外围触发的扩大操作postProcessBeanDefinitionRegistry是:通过Spring外部的一个ConfigurationClassPostProcessor,补充了新的BeanDefinition。

当执行完这个类的扩大操作后,容器的BeanDefinitionMap中多了很多BeanDefinition,有SpringMVC相干的,有MyBatis相干、有咱们本人定义的Controller和Service相干等。

那咱们大体就能够分为两步来看,

1) 本人定义的Controller和Service相干的BeanDefinition增加
2) starter、其余框架的BeanDefinition增加

本人定义的Controller和Service相干的BeanDefinition如何增加的?

在看第一步之前,你能够思考下,咱们定义的Bean是不是通常有以下几种

@Bean+@Configuration注解定义的,@Service,@Controller等注解定义的、也有用xml、groovy定义的bean

而且能够通过@Import,@ImportResource导入其余的xml或者JavaConfig定义的Bean,@ComponentScan指定扫描Bean的门路等等。

也就是说有一大堆注解须要咱们剖析和解析。这个是须要一个解析器和扫描器来进行的。就相似于之前咱们提到的Reader和Scanner。

那么接下来,咱们看下第一步,本人定义的Controller和Service相干的BeanDefinition是如何被增加的?

方才咱们剖析到,有一大堆注解须要ConfigurationClassPostProcessor剖析和解析,那ConfigurationClassPostProcessor中外围的那几个组件来负责做这些事件的呢?

让我先来看下ConfigurationClassPostProcessor它扩大办法的脉络:

@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {   int registryId = System.identityHashCode(registry);   if (this.registriesPostProcessed.contains(registryId)) {      throw new IllegalStateException(            "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);   }   if (this.factoriesPostProcessed.contains(registryId)) {      throw new IllegalStateException(            "postProcessBeanFactory already called on this post-processor against " + registry);   }   this.registriesPostProcessed.add(registryId);   processConfigBeanDefinitions(registry);}

办法脉络其实很简略,外围触发了processConfigBeanDefinitions这个办法,其余的if判断只是些校验而已。

而触发的这个办法内容就比拟多了:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();        String[] candidateNames = registry.getBeanDefinitionNames();        for (String beanName : candidateNames) {            BeanDefinition beanDef = registry.getBeanDefinition(beanName);            if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {                if (logger.isDebugEnabled()) {                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);                }            }            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));            }        }        // Return immediately if no @Configuration classes were found        if (configCandidates.isEmpty()) {            return;        }        // Sort by previously determined @Order value, if applicable        configCandidates.sort((bd1, bd2) -> {            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());            return Integer.compare(i1, i2);        });        // Detect any custom bean name generation strategy supplied through the enclosing application context        SingletonBeanRegistry sbr = null;        if (registry instanceof SingletonBeanRegistry) {            sbr = (SingletonBeanRegistry) registry;            if (!this.localBeanNameGeneratorSet) {                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(                        AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);                if (generator != null) {                    this.componentScanBeanNameGenerator = generator;                    this.importBeanNameGenerator = generator;                }            }        }        if (this.environment == null) {            this.environment = new StandardEnvironment();        }        // Parse each @Configuration class        ConfigurationClassParser parser = new ConfigurationClassParser(                this.metadataReaderFactory, this.problemReporter, this.environment,                this.resourceLoader, this.componentScanBeanNameGenerator, registry);        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());        do {            parser.parse(candidates);            parser.validate();            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());            configClasses.removeAll(alreadyParsed);            // Read the model and create bean definitions based on its content            if (this.reader == null) {                this.reader = new ConfigurationClassBeanDefinitionReader(                        registry, this.sourceExtractor, this.resourceLoader, this.environment,                        this.importBeanNameGenerator, parser.getImportRegistry());            }            this.reader.loadBeanDefinitions(configClasses);            alreadyParsed.addAll(configClasses);            candidates.clear();            if (registry.getBeanDefinitionCount() > candidateNames.length) {                String[] newCandidateNames = registry.getBeanDefinitionNames();                Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));                Set<String> alreadyParsedClasses = new HashSet<>();                for (ConfigurationClass configurationClass : alreadyParsed) {                    alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());                }                for (String candidateName : newCandidateNames) {                    if (!oldCandidateNames.contains(candidateName)) {                        BeanDefinition bd = registry.getBeanDefinition(candidateName);                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {                            candidates.add(new BeanDefinitionHolder(bd, candidateName));                        }                    }                }                candidateNames = newCandidateNames;            }        }        while (!candidates.isEmpty());        // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes        if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {            sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());        }        if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {            // Clear cache in externally provided MetadataReaderFactory; this is a no-op            // for a shared cache since it'll be cleared by the ApplicationContext.            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();        }    }

办法长或者不好了解,没有关系。你用我教你的思维剖析就好,

依照for循环和if,划分脉络,抓大放小后,最外围的逻辑能够分为如下3点:

1)第一个for循环:获取BeanDefinitionMap所有的beanName,查找出标记了@Configuration注解的BeanDefinition,这里找到的其实是learnSpringBootApplication

2)if逻辑,抉择了BeanNameGenerator,bean的名称生成器相干的设置

3)do-while,创立了ConfigurationClassParser和ConfigurationClassBeanDefinitionReader去扫描和解析ClassPath下的BeanDefinition

整体如下图所示:

这里咱们要强调的是,下面这段逻辑在解决的是咱们自定义的Bean,包含Controller、Service和整合其余技术配置的Bean的。

你能够思考下,下面的解决思路就是,查找到BeanDefination,解析和增加BeanDefination。

从哪里开始查找BeanDefination呢?

通过之前prepare和create容器context的时候,通过 Initializers减少了默认的internalBeanDefination和LearnSpringBootApplication的BeanDefination。

(遗记的同学,能够回顾下prepare和create容器,成长记5和6)

ConfigurationClassPostProcessor这里就是遍历之前的BeanDefinationMap汇合,它查找的是所有蕴含@Configuration的BeanDefination

最终查找到的只有一个LearnSpringBootApplication的BeanDefination。

如下图所示:

怎么解析出BeanDefination?

当晓得了次要是找到了LearnSpringBootApplication这个BeanDefination,以这个为入口开始剖析解析

javaConfig定义的bean,其实实质是找到所有@Configuration的配置类,@ComponentScan等注解的类,挨个解析它们定义范畴的Bean。

xml和groovy也有对应的查找形式,就不赘述了。

具体怎么处解析咱们定义的Bean的呢?

必定要解决很多注解的,比方@ComponentScan注解、@ImportSource等等注解。

次要应用了的组件次要就是ConfigurationClassBeanDefinitionReader、ConfigurationClassParser,通过组件的parse办法来执行解析的。

详情如下图所示:

执行到这里,本人定义的Controller和Service相干的BeanDefinition就增加完了。

根本就是从Resource->ClassLoader->注解解析,筛选->ConfigurationClass->BeanDefinition

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponentsresources = {Resource[7]@4174}  0 = {FileSystemResource@4181} "file [D:\Repository\Gitee\learn-project\learn-spring-projects\learn-springboot\target\classes\org\mfm\learn\springboot\LearnSpringBootApplication.class]" 1 = {FileSystemResource@4185} "file [D:\Repository\Gitee\learn-project\learn-spring-projects\learn-springboot\target\classes\org\mfm\learn\springboot\controller\UserController.class]" 2 = {FileSystemResource@4186} "file [D:\Repository\Gitee\learn-project\learn-spring-projects\learn-springboot\target\classes\org\mfm\learn\springboot\mapper\UserMapper.class]" 3 = {FileSystemResource@4187} "file [D:\Repository\Gitee\learn-project\learn-spring-projects\learn-springboot\target\classes\org\mfm\learn\springboot\model\User.class]" 4 = {FileSystemResource@4188} "file [D:\Repository\Gitee\learn-project\learn-spring-projects\learn-springboot\target\classes\org\mfm\learn\springboot\service\IUserService.class]" 5 = {FileSystemResource@4189} "file [D:\Repository\Gitee\learn-project\learn-spring-projects\learn-springboot\target\classes\org\mfm\learn\springboot\service\MyBeanPostProcessor.class]" 6 = {FileSystemResource@4190} "file [D:\Repository\Gitee\learn-project\learn-spring-projects\learn-springboot\target\classes\org\mfm\learn\springboot\service\UserServiceImpl.class]"
{ConfigurationClass@4654} "ConfigurationClass: beanName 'userController', class path resource [org/mfm/learn/springboot/controller/UserController.class]" -> {ConfigurationClass@4654} "ConfigurationClass: beanName 'userController', class path resource [org/mfm/learn/springboot/controller/UserController.class]"{ConfigurationClass@4853} "ConfigurationClass: beanName 'myBeanPostProcessor', class path resource [org/mfm/learn/springboot/service/MyBeanPostProcessor.class]" ->
beanDefinitionNames = {ArrayList@4316}  size = 10 0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor" 1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor" 2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor" 3 = "org.springframework.context.event.internalEventListenerProcessor" 4 = "org.springframework.context.event.internalEventListenerFactory" 5 = "learnSpringBootApplication" 6 = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory" 7 = "userController" 8 = "myBeanPostProcessor" 9 = "userServiceImpl"

starter和其余框架的BeanDefinition如何增加的?

通过下面的剖析你应该晓得了ConfigurationClassPostProcessor是通过ConfigurationClassParser的parse办法查找和解析ClassPath下的BeanDefination

次要分为两步:

第一步次要是增加本人定义的Controller和Service相干的BeanDefinition

第二步次要做了什么?

答案是:增加了starter中其余框架的BeanDefinition如何增加的

那通过什么增加starter中的BeanDefinition呢?

在之前第一步解析import注解的时候,会扫描进去一个AutoConfigurationImportSelector。通过这个Selector会补充增加starter中的BeanDefinition

如下图所示:

AutoConfigurationImportSelector具体怎么补充starter中的BeanDefinition,其实一句话概括就是查找了所有ClassPath下的META-INF/spring.factories定义的EnableAutoConfiguration.class,通过条件注解解析加载出对应的主动配置,将配置中的@Bean加载为BeanDefinition

我通过一张图给大家解释下:

这里有大堆的封装,不是十分重要,能够跳过,大家晓得封装了之前扫描import注解获取的AutoConfigurationImportSelector这个组件就能够了。

上图外围就是读取了META-INF/spring.factories中定义的一对AutoConfiguration。有了这些AutoConfiguration,天然就能够解析出对应的BeanDefinition了。

思考:ConfigurationClassPostProcessor的增加BeanDefination的设计

ConfigurationClassParser,外部应用了Scanner,扫描了ClassPath下简直所有的BeanDefination,本人定义的注解bean也好,内部的基于条件注解的主动配置也好,都会扫描到,它们通通为Resource资源,只不过这些Resource资源示意的是Bean的配置类而已,个别应用Java定义的话都是ConfigurationClasss,它们作为候选者,通过Reader解析器解析后,将所有的BeanDefination放入到容器中。

其实合乎咱们之前将Spring容器形象设计的思维,Resource-->Reader-->BeanDefination,只不过它封装很多组件类来实现这个过程而已。

通过思考后,你能够抓住重点,详情总结下。最终SpringBoot的Starter进行主动拆卸配置的外围流程和设计咱们能够详情如下图所示:

第三方技术如何进行扩大的

思考:mybatis的Mapper如何被增加的?

之前咱们增加了很多通过注解定义bean,无论是咱们本人些的@Service、@Controller定义的Bean,还是starter中的@Bean。

可是还有一些Bean没有注解,也能被增加,比方mybatis的mapper。

public interface UserMapper extends BaseMapper<User> {}@MapperScan("org.mfm.learn.springboot.mapper")@SpringBootApplicationpublic class LearnSpringBootApplication {}

其实如果你理解无论是注解定义的还是没有注解的,其实在Spring看来都是一样的,因为它们都是Resource,我是依据不同的Scanner扫描到不同的Resource资源,通过指定的形式解析进去一些想要的Resource为BeanDefination而已。

那么你如果想增加额定的BeanDefination,能够本人定义Scanner来补充资源,定义指定的形式增加BeanDefination就行。

mybatis就是这么干的。

通过下面的代码你其实能够看到@MapperScan注解其实定义了本人的Scanner:MapperScannerRegistrar

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(MapperScannerRegistrar.class)@Repeatable(MapperScans.class)public @interface MapperScan {

MapperScannerRegistrar类实现了要害的两个接口ImportBeanDefinitionRegistrar, ResourceLoaderAware。

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {}

你能够猜测下:

一个应该Spring设计对增加额定BeanDefinition设计的接口ImportBeanDefinitionRegistrar

一个应该是ResourceLoaderAware,设置好ResourceLoader这个属性,你还记得ResourceLoader,它是不是封装ClassLoader,能够Classpath查找Resource。

因为Scanner次要的作用就是查找和过滤资源。

晓得了这个逻辑了解Mapper怎么增加的就不难了。咱们来看下代码:

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {@Override  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {    AnnotationAttributes mapperScanAttrs = AnnotationAttributes        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));    if (mapperScanAttrs != null) {      registerBeanDefinitions(mapperScanAttrs, registry);    }  }  void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);    // this check is needed in Spring 3.1    Optional.ofNullable(resourceLoader).ifPresent(scanner::setResourceLoader);    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");    if (!Annotation.class.equals(annotationClass)) {      scanner.setAnnotationClass(annotationClass);    }    Class<?> markerInterface = annoAttrs.getClass("markerInterface");    if (!Class.class.equals(markerInterface)) {      scanner.setMarkerInterface(markerInterface);    }    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");    if (!BeanNameGenerator.class.equals(generatorClass)) {      scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));    }    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {      scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);    }    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));    List<String> basePackages = new ArrayList<>();    basePackages.addAll(        Arrays.stream(annoAttrs.getStringArray("value"))            .filter(StringUtils::hasText)            .collect(Collectors.toList()));    basePackages.addAll(        Arrays.stream(annoAttrs.getStringArray("basePackages"))            .filter(StringUtils::hasText)            .collect(Collectors.toList()));    basePackages.addAll(        Arrays.stream(annoAttrs.getClassArray("basePackageClasses"))            .map(ClassUtils::getPackageName)            .collect(Collectors.toList()));    scanner.registerFilters();    scanner.doScan(StringUtils.toStringArray(basePackages));  }  }

能够看到MapperScannerRegistrar中次要执行是通过ClassPathMapperScanner来执行的,而且解析了@MapperScan中的属性,看看是否要过滤那些Bean之类的。

有了MapperScannerRegistrar,那它什么时候执行的呢?通过一张图我给大家讲下:

能够看到就是在咱们之前剖析触发扩大操作的时候,在执行ConfigurationClassBeanDefinitionReader#loadBeanDefinitions()是,会查看到标记了@MapperScan注解的ConfigurationClass,解决这个类的时候,会执行MapperScannerRegistrar。

基于ImportBeanDefinitionRegistrar的扩大

Spring容器有很多扩大点,方才看到MyBatis利用了ImportBeanDefinitionRegistrar进行扩大,还有很多技术都是用这种形式进行一些扩大。

比方Qconfig 、Sedis 、QSchedule 等

Qconfig QConfigAutoConfiguration

@Configuration@Import(QConfigAutoConfiguration.Register.class)@Internalpublic class QConfigAutoConfiguration {}

Sedis DbaccessAutoConfiguration

@Configuration@Import(DbaccessAutoConfiguration.Register.class)public class DbaccessAutoConfiguration {}

QSchedule QScheduleAutoConfiguration

@Configuration@Import(QScheduleAutoConfiguration.Register.class)public class QScheduleAutoConfiguration {}

咱们以Qconfig 举例,通过ImportBeanDefinitionRegistrar能够进行什么样的扩大呢?如下所示:

@Configuration@Import(QConfigAutoConfiguration.Register.class)public class QConfigAutoConfiguration {        class Register implements ImportBeanDefinitionRegistrar{        public Register() {            //读取本地配置                      //从配置核心获取配置                 }        //增加要害的beanDefinition        @Override        public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {                   }           }}

其实无论如何,你要透过景象看到实质,扩大操作最终,实质都是为了给容器补充一些BeanDefinition、一些Bean,为Bean设置一些属性。

而这些Bean实现什么性能,都能够,能够mq相干,配置相干,数据拜访相干都能够,这就是Spring容器帮咱们创建对象,对象的保护又不失去灵活性,这一点是十分好的。当然前提是你得熟练掌握Spring容器。

基于BeanFactoryPostProcessor的扩大

咱们当初始终在整个run办法的流程中剖析invokeBeanFactoryPostProcessors它的外围逻辑,后面通过invokeBeanFactoryPostProcessors中的if-else逻辑执行了很多扩大逻辑。

而invokeBeanFactoryPostProcessors除了if-else中的逻辑执行,其实还有外层的3个for循环须要执行。

上一节咱们剖析过for循环是在执行BeanFactoryPostProcessor的一个扩大操作。能够是之前咱们曾经将SpringBoot外部的BeanFactoryPostProcessor依照程序执行过了。前面要执行的这些BeanFactoryPostProcessor哪里来的呢?

其实很简略,咱们执行if-else的逻辑后,触发了很多主动拆卸配置和第三方的扩大操作,补充了一大堆BeanDefinition,这些BeanDefinition如果有新的BeanFactoryPostProcessor,就须要进行再次触发下BeanFactoryPostProcessor的扩大操作了。

至于触发第三方技术定义的这些BeanFactoryPostProcessor,能够做什么,其实就很多了。比方增加、批改BeanDefinition,解析本人第三方的配置文件等等。

这里我就不具体举例了,简略详情了下它执行的逻辑,整体如下图所示:

小结

到这里,咱们就剖析完了SpringBoot十分外围的性能,通过剖析invokeBeanFactoryPostProcessors的扩大点的执行,剖析了SpringBoot主动拆卸配置的原理。

其实这里最要害的不是SpringBoot主动拆卸的原理,最要害的次要是两点:

第一点:主动拆卸的要害其实是基于扩大点接口BeanFactoryPostProcessor的触发设计,根于Resource到BeanDefinition的形象设计。其余的不过是绑定到了某个类或者办法的执行流程中而已,或者基于约定查找了固定名称的配置文件而已。

第二点:一个好的框架,是不断完善的,在一些外围的操作中,如果想要灵便,仍能够做额定的扩大设计。ConfigurationClass解析就是很好的例子,通过ImportBeanDefinitionRegistrar等扩大设计,灵便的凋谢进去,不便让第三方技术对Bean配置的做补充等。

最初留一个小的思考:SpringMVC罕用的外围组件的BeanDefinition是什么时候加载的呢?如果了解了明天的内容,置信你必定能答复上来。

答上来的话,其实你也就懂了SpringMVC如何和SpringBoot整合的了。

好,咱们下节再见!

本文由博客一文多发平台 OpenWrite 公布!