1、@SpringBootApplication注解
springboot
启动类上都会配置@SpringBootApplication
注解,用来加载配置
@SpringBootApplication
@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 {
……
}
2、@EnableAutoConfiguration注解
我们可以看到@SpringBootApplication
是组合注解,其中@EnableAutoConfiguration
注解进行自动配置,加载bean到IOC容器。
@EnableAutoConfiguration
@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 {};//排除指定class
String[] excludeName() default {};//排除指定类名
}
@EnableAutoConfiguration
由两个关键注解组成@AutoConfigurationPackage
、
@Import(AutoConfigurationImportSelector.class)
,下面我们分别解释下这两个注解。
3、@AutoConfigurationPackage注解
/**
* Registers packages with {@link AutoConfigurationPackages}.
* When no {@link #basePackages base packages} or {@link #basePackageClasses base package classes} are specified, the
* package of the annotated class is registered.
* 注册在basePackages和basePackageClasses指定的class,如果没有指定那么注册
* 这个注解类修饰的类所在的包
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
@Import(AutoConfigurationPackages.Registrar.class)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
把启动类所在的包注册进去了
image.png
4、@Import(AutoConfigurationImportSelector.class)
自动装配的核心是扫描约定目录下的文件进行解析,解析完成之后把得到的Configuration配置类通过ImportSelector进行导入,从而完成Bean的自动装配过程。springboot由AutoConfigurationImportSelector来实现的。下面进行详细解析:
image.png
selectImports
方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
最终调用到getAutoConfigurationEntry
方法获取所有需要自动装配的配置类。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
- getAttributes获得@EnableAutoConfiguration注解中的属性exclude、excludeName等
- getCandidateConfigurations获得所有自动装配的配置类
- removeDuplicates去除重复的配置项
- getExclusions根据@EnableAutoConfiguration注解中的exclude、excludeName属性,把不需要自动装配的配置类移除。
-
最后返回多层判断和过滤后的配置类集合
总的来说,它先获取所有类的配置,通过去重、exclude排除等操作,得到最终需要实现自动装配的配置类。这里需要关注的是getCandidateConfigurations
,它是获取配置类的核心方法。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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内部提供的一种约定俗成的加载方式,类似于Java中SPI(Service Provider Interface)。简单来说,它会扫描META-INF/spring.factories
问价,spring.factories
问价中的数据以key=value形式存储。在这个场景中,Key对应EnableAutoConfiguration,Value是多个配置类,也就是getCandidateConfigurations方法返回的值。
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
5、总结
- 通过
@Import(AutoConfigurationImportSelector.class)
实现配置类的导入 AutoConfigurationImportSelector
实现了ImportSelector接口,重写了selectImports,实现选择性批量配置了的装配。- 通过Spting提供的SpringFactoriesLoader机制,扫描classpath路径下的
META-INF/spring.factories
,读取需要实现自动装配的配置类。 - 通过条件筛选,把不符合条件的配置类移除,最终完成自动装配。
Spring Cloud Alibaba 微服务原理与实战 ——谭锋(Mic)著
网友评论