SpringBoot的自动加载
@SpringBootApplication
我们在SpringBoot的启动类(xxxApplication.class)上面可以看到注解 @SpringBootApplication ;
该注解表示这是一个SpringBootApplication的应用启动类的入口.类似于Java的main()方法。
进到 SpringBootApplication 注解内部。
package org. springframework. boot. autoconfigure ; import . . . @Target ( ElementType . TYPE) @Retention ( RetentionPolicy . RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan ( excludeFilters = { @Filter ( type = FilterType . CUSTOM, classes = TypeExcludeFilter . class ) , @Filter ( type = FilterType . CUSTOM, classes = AutoConfigurationExcludeFilter . class ) } ) public @interface SpringBootApplication { . . . }
在这个类上我们可以发现 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan 这三个比较不一样的注解。
@SpringBootConfiguration
进到 SpringBootConfiguration注解内部。
package org. springframework. boot ; import . . . @Target ( ElementType . TYPE) @Retention ( RetentionPolicy . RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { . . . }
在这里我们可以看到 @Configuration 这个注解。
其作用时告诉SpringBoot:SpringBootConfiguration 是一个配置类文件。
所以 @SpringBootConfiguration 作用同样时告诉SpringBoot:SpringBootApplication 是一个配置类文件。
@EnableAutoConfiguration
进到 EnableAutoConfiguration 注解内部。
通过类的名字我们可以知道这是开启自动配置的注解。
package org. springframework. boot. autoconfigure ; import . . . @Target ( ElementType . TYPE) @Retention ( RetentionPolicy . RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import ( AutoConfigurationImportSelector . class ) public @interface EnableAutoConfiguration { . . . }
在这里我们可以看到 @AutoConfigurationPackage 以及 @Import(AutoConfigurationImportSelector.class) 这个注解。
@AutoConfigurationPackage
进到 AutoConfigurationPackage 注解内部。
通过名字我们可以知道这是自动配置包的注解
package org. springframework. boot. autoconfigure ; import . . . @Target ( ElementType . TYPE) @Retention ( RetentionPolicy . RUNTIME) @Documented @Inherited @Import ( AutoConfigurationPackages. Registrar . class ) public @interface AutoConfigurationPackage { . . . }
在这里我们可以看到 @Import(AutoConfigurationPackages.Registrar.class) 这个注解。
@Import
其功能就是和Spring XML 里面的 一样.。@Import 注解是用来导入配置类或者一些需要前置加载的类
AutoConfigurationPackages.Registrar
在其内部发现
@Override public void registerBeanDefinitions ( AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register ( registry, new PackageImports ( metadata) . getPackageNames ( ) . toArray ( new String [ 0 ] ) ) ; }
debug调试打断点发现:通过metadata 拿到对应启动类所在包放进数组。并通过register方法将 包名/路径 加载进Spring的Ioc容器
@Override public static void register ( BeanDefinitionRegistry registry, String . . . packageNames) { if ( registry. containsBeanDefinition ( BEAN) ) { BeanDefinition beanDefinition = registry. getBeanDefinition ( BEAN) ; ConstructorArgumentValues constructorArguments = beanDefinition. getConstructorArgumentValues ( ) ; constructorArguments. addIndexedArgumentValue ( 0 , addBasePackages ( constructorArguments, packageNames) ) ; } else { GenericBeanDefinition beanDefinition = new GenericBeanDefinition ( ) ; beanDefinition. setBeanClass ( BasePackages . class ) ; beanDefinition. getConstructorArgumentValues ( ) . addIndexedArgumentValue ( 0 , packageNames) ; beanDefinition. setRole ( BeanDefinition . ROLE_INFRASTRUCTURE) ; registry. registerBeanDefinition ( BEAN, beanDefinition) ; } }
AutoConfigurationImportSelector
通过名称不难发现,此处是 导入选择自动配置 (自动装配)。
在该类内部发现 获取候选配置
protected List < String > getCandidateConfigurations ( AnnotationMetadata metadata, AnnotationAttributes attributes) { List < String > configurations &#61; SpringFactoriesLoader . loadFactoryNames ( getSpringFactoriesLoaderFactoryClass ( ) , getBeanClassLoader ( ) ) ; Assert . notEmpty ( configurations, "No auto configuration classes found in META-INF/spring.factories. If you " &#43; "are using a custom packaging, make sure that file is correct." ) ; return configurations; }
其内部 loadFactoryNames 调用了getSpringFactoriesLoaderFactoryClass
getSpringFactoriesLoaderFactoryClass
通过代码发现返回了EnableAutoConfiguration 的类
protected Class < ? > getSpringFactoriesLoaderFactoryClass ( ) { return EnableAutoConfiguration . class ; }
loadFactoryNames
该方法是加载工厂名&#xff0c;并在内部调用了加载spring的工厂放进配置类文件EnableAutoConfiguration
public static List < String > loadFactoryNames ( Class < ? > factoryType, &#64;Nullable ClassLoader classLoader) { String factoryTypeName &#61; factoryType. getName ( ) ; return ( List ) loadSpringFactories ( classLoader) . getOrDefault ( factoryTypeName, Collections . emptyList ( ) ) ; }
loadSpringFactories 获取自动装配的url Enumeration urls &#61; classLoader !&#61; null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
private static Map < String , List < String > > loadSpringFactories ( &#64;Nullable ClassLoader classLoader) { MultiValueMap < String , String > result &#61; ( MultiValueMap ) cache. get ( classLoader) ; if ( result !&#61; null ) { return result; } else { try { Enumeration < URL> urls &#61; classLoader !&#61; null ? classLoader. getResources ( "META-INF/spring.factories" ) : ClassLoader . getSystemResources ( "META-INF/spring.factories" ) ; LinkedMultiValueMap result &#61; new LinkedMultiValueMap ( ) ; while ( urls. hasMoreElements ( ) ) { URL url &#61; ( URL) urls. nextElement ( ) ; UrlResource resource &#61; new UrlResource ( url) ; Properties properties &#61; PropertiesLoaderUtils . loadProperties ( resource) ; Iterator var6 &#61; properties. entrySet ( ) . iterator ( ) ; while ( var6. hasNext ( ) ) { Entry < ? , ? > entry &#61; ( Entry ) var6. next ( ) ; String factoryTypeName &#61; ( ( String ) entry. getKey ( ) ) . trim ( ) ; String [ ] var9 &#61; StringUtils . commaDelimitedListToStringArray ( ( String ) entry. getValue ( ) ) ; int var10 &#61; var9. length; for ( int var11 &#61; 0 ; var11 < var10; &#43;&#43; var11) { String factoryImplementationName &#61; var9[ var11] ; result. add ( factoryTypeName, factoryImplementationName. trim ( ) ) ; } } } cache. put ( classLoader, result) ; return result; } catch ( IOException var13) { throw new IllegalArgumentException ( "Unable to load factories from location [META-INF/spring.factories]" , var13) ; } } }
此时发现获取的文件"META-INF/spring.factories" 在同包下发现相关文件 其内部包含非常多的xxxAutoConfiguration&#xff0c;任意找一个我们所熟悉的数据库的自动配置&#xff1a;org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
根据其repository path 得到对应文件
package org. springframework. boot. autoconfigure. jdbc ; import . . . &#64;Configuration ( proxyBeanMethods &#61; false ) &#64;ConditionalOnClass ( { DataSource . class , EmbeddedDatabaseType . class } ) &#64;ConditionalOnMissingBean ( type &#61; "io.r2dbc.spi.ConnectionFactory" ) &#64;EnableConfigurationProperties ( DataSourceProperties . class ) &#64;Import ( { DataSourcePoolMetadataProvidersConfiguration . class , DataSourceInitializationConfiguration . class } ) public class DataSourceAutoConfiguration { . . . }
在其内部发现 &#64;ConditionOnXXX 以及 &#64;EnableConfigurationProperties(DataSourceProperties.class)
&#64;ConditionOnXXX
在某情况下该自动配置类生效&#xff1a;
&#64;EnableConfigurationProperties
作用&#xff1a;绑定对应配置文件类&#xff0c;提供自动配置类所需要的配置文件中的相关属性。
xxxAutoConfiguration.class 与 xxxProperties.class
不难发现 xxxAutoConfiguration 总是与 xxxProperties 成对出现。
xxxAutoConfiguration自动装配&#xff0c;给容器添加相关组件。 xxxProperties获取所需相关属性 &#64;ComponentScan
这个注解在Spring中很重要 ,它对应XML配置中的元素。
作用&#xff1a;自动扫描并加载符合条件的组件或者bean &#xff0c; 将这个bean定义加载到IOC容器中