让SpringBoot自动化配置不再神秘 (2)

这里暂时不讨论@ComponentScan

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ···省略··· }

这个注解又使用了两个注解,分别是@AutoConfigurationPackage和@Import

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }

可以发现,这两个注解最终都指向了同一个注解@Import

@Import是Annotation时代的<import/>,作用是向BeanDefinitionRegistry注册Bean的。

所以@EnableAutoConfiguration这个注解一共注册了两个Bean,分别是:AutoConfigurationPackages.Registrar.class和AutoConfigurationImportSelector.class

先说说AutoConfigurationPackages.Registrar的用处

这个类就干一个事,注册一个Bean,这个Bean就是org.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages,它有一个参数,这个参数是使用了@AutoConfigurationPackage这个注解的类所在的包路径。有了这个包路径后,就会扫描这个包下的所有class文件,然后将需要注册到Bean容器的类,给注册进去。

具体可以参见这里 org.springframework.boot.autoconfigure.AutoConfigurationPackages#register

这里就解释了为什么有时候主配置类放的位置不对,导致有些类没被Spring容器纳入管理

桃花源

经历了一番折腾,就要进入桃花源了

AutoConfigurationImportSelector就是那最后一层窗户纸

// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 为了加载spring-boot-autoconfiguration包下的配置文件META-INF/spring-autoconfigure-metadata.properties // 这里配置的主要是一些SpringBoot启动时用到的一些@ConditionOnClass的配置 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); // 这里的AutoConfigurationEntry,就包含了所有的导入的需要被实例化的Bean AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); // 返回这些被导入Bean的类全限定名数组 return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } ··· 省略 ··· // 获取所有的需要导入的Bean,这些被导入的Bean就是各个组件需要自动化配置的启动点 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); ··· 省略 ··· return new AutoConfigurationEntry(configurations, exclusions); } protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { // 使用SpringFactoriesLoader#loadFactoryNames方法,从所有的包及classpath目录下,查找META-INF/spring.factories文件,且名称为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置 List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; } }

最终这些配置在META-INF/spring.factories中需要自动配置的类,就会被注册到Spring Bean容器中,然后被实例化,调用初始化方法等!

这些做自动配置的类,基本都会通过实现各种Aware接口,获取到Spring Framework中的BeanFactory,ApplicationContext等等所有的一些框架内的组件,用于后面使用。

之后完成自己框架的一些初始化工作,主要就是将原先和Spring整合时,需要手动配置的那些,在这里通过编程式的方式,给做了。

这样,就完成了所谓的自动化配置,全程不需要我们的任何参与。

PS: 这个仅仅是做了一个通用的配置,让用户可以在不做任何配置的情况下能直接使用。但是一些个性化的配置,还是需要通过配置文件的方式,写入配置。对于这部分配置的处理,SpringBoot也都给揽下了

总结

整体看下来,SpringBoot干的这些,更像是一个体力活,将于Spring集成的那么多三方库的配置,使用代码全部实现了一遍,其使用的核心功能,依然是Spring Framework的那些东西。

但是这个体力活是为使用者省下的,也让Spring Framework更加的具有活力了。

同时微服务的兴起,也是Spring为了顺势而必须作出的一个改变,也可以说为Spring在微服务领域立下了汗马功劳!

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsswzj.html