@SpringbootConfiguration
@SpringbootConfiguration注解等同于以下下三个注解:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
@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 {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
/**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
@SpringBootConfiguration
可以看到SpringBootConfiguration 等同于使用了@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@EnableAutoConfiguration
@EnableAutoConfiguration会根据classpath以及定义的Bean来帮你加载你想要的bean。
可以通过spring.autoconfigure.exclude来排除掉不想自动加载的bean。
且Auto-configuration发生在自定义的bean都被注册好了之后。
另外最好将带有@EnableAutoConfiguration的类放在root package,这样就能扫描所有子包下面的类。
auto-configuration的bean大多数都是带有@ConditionalOnClass and @ConditionalOnMissingBean 注解的bean。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationImportSelector
这个类实现了DeferredImportSelector被import进来,内部会调用getCandidateConfigurations()来加载所有的auto-configuration beans
//首先会从spring-boot-autoconfigure的jar文件里的META-INF/spring-autoconfigure-metadata.properties里面找到配置并组装成AutoConfigurationMetadata
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获得注解的属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//调用getCandidateConfigurations来获取classpath中存在的auto-configure beans
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//去除重复的
configurations = removeDuplicates(configurations);
//根据exclude来剔除不需要的
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//再根据AutoConfigurationMetadata来进行filter
configurations = filter(configurations, autoConfigurationMetadata);
//触发auto-configureimport的事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
//内部还是通过SpringFactoriesLoader.loadFactoryNames
// 来加载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;
}
从下面图中能看到SpringFactoriesLoader从spring.factory里找到207个auto-configuration的beans。

AutoConfigurationImportSelector核心功能就是获取spring.factories中EnableAutoConfiguration所对应的Configuration类列表,由@EnableAutoConfiguration注解中的exclude/excludeName参数筛选一遍,再由AutoConfigurationImportFilter类所有实例筛选一遍,得到最终的用于Import的configuration和exclusion。
该函数是被谁调用的呢?在org.springframework.context.annotation.ConfigurationClassParser类中被processImports()调用,而processImports()函数被doProcessConfigurationClass()调用。
关于ConfigurationClassParser请参考Spring Annotation IOC
@ComponentScan
指定扫描basePackages的路径,具体可以查看@Configuration的javadoc文档。
网友评论