《深入探究 @SpringBootApplication 注解的内部原理》
@SpringBootApplication
注解涵盖了 Spring Boot 的包扫描原理、自动装配原理等众多重要原理。接下来,我们将对该注解展开深入且详尽的研究。而研究上述原理的关键,在于剖析
@SpringBootApplication
内部的构成结构,如下图:
下面对@SpringBootConfiguration和@EnableAutoConfiguration进行详解。
一、@SpringBootConfiguration注解
内部结构:
@Configuration是Spring的一个注解,其修饰的类会加入Spring容器。这就说明SpringBoot的启动类会加入Spring容器。
进入内部:
该注解会被注入到IOC容器中
二、@EnableAutoConfiguration注解
内部结构:
@AutoConfigurationPackage注解:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class)public@interfaceAutoConfigurationPackage{}
其内部@Import进来的类AutoConfigurationPackages.Registrar类:
源码如下:
staticclassRegistrarimplementsImportBeanDefinitionRegistrar,DeterminableImports{@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry){register(registry,newPackageImport(metadata).getPackageName());}@OverridepublicSet<Object>determineImports(AnnotationMetadata metadata){returnCollections.singleton(newPackageImport(metadata));}}
进入registerBeanDefinitions方法中的register方法:
publicstaticvoidregister(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 =newGenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);}}
通过断点,查看packageNames参数的传入值:
可见是在启动类中配置的scanBasePackages属性的包。
程序进入了else条件块儿,执行如下代码:
GenericBeanDefinition beanDefinition =newGenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
该步骤就是创建BeanDefinition对象,然后将其注册到BeanDefinition注册器中,详情如下:
可以看到,这个BeanDefinition封装的是一个Package对象。所以,BeanDefinition不只能封装类的属性,还可以封装整个包的属性。
@Import(AutoConfigurationImportSelector.class):
进入AutoConfigurationImportSelector类:
AutoConfigurationImportSelector
是自动配置的关键类。其主要功能是选择需要导入的自动配置类。
1.选择配置类:通过
selectImports()
方法确定需要导入的自动配置类。
2.加载配置条目:调用
getAutoConfigurationEntry()
方法来加载自动配置类的元数据。
集合configurations长度为145,所以共有145个配置类可以选择,在使用时返回对应需要的配置类
3.解析配置类:通过
getCandidateConfigurations()
方法从
spring.factories
文件中加载所有可用的自动配置类,源码如下:
protectedList<String>getCandidateConfigurations(AnnotationMetadata metadata,AnnotationAttributes attributes){List<String> configurations =newArrayList<>(SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class,getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations,"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "+"are using a custom packaging, make sure that file is correct.");return configurations;}
我们进入到getCandidateConfigurations()方法中可以看到是使用SpringFactoriesLoader从spring.factories文件中加载指定类型的工厂类名,然后通过ImportCandidates.load方法加载所有AutoConfiguration类,并将这些类名添加到列表中。
SpringFactoriesLoader详解
SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置,源码如下:
它配合@EnableAutoConfiguration使用的话,它更多是提供一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类
所以,@EnableAutoConfiguration自动配置:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。
总结:
Spring Boot 的自动配置机制凭借 @EnableAutoConfiguration 注解与 AutoConfigurationImportSelector 类,达成了对 spring.factories 文件里所定义的自动配置类的智能化加载。此机制使开发者能够将精力集中于业务逻辑,无需在基础框架配置上耗费过多心思,大幅提升了开发效率,增强了代码的可维护性。
经由本文的阐述,您应当能够更透彻地领会 Spring Boot 自动配置隐藏在背后的技术要点,并且能够更为高效地运用这一特性来搭建自身的应用。
版权归原作者 Nonullpoint. 所有, 如有侵权,请联系我们删除。