通过ImportSelector和@Import实现
以下以EnableAutoConfiguration为例说明各类Enable实现过程
ImportSelector说明
org.springframework.context.annotation.ImportSelector用于定义哪些被@Configuration 注解的类应该被导入。
public interface ImportSelector {
/**
* 基于@Configuration 类的注解元数据判断类是否应该被导入、
* @return 返回需要被导入的@Configuration类的名称,如果为空数组表示没有需要导入的@Configuration类
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
/**
* 返回一个predicate,predicate参数是selectImports发现需要导入的类名称
* 如果predicate返回true,则该类不会被导入
*/
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
ImportSelector的实现可以通过继承EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口或者单个构件赵晗,来获得以下对象实例
- Environment
- BeanFactory
- ClassLoader
- ResourceLoader
EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//
@AutoConfigurationPackage
// 注意:使用import注解导入ImportSelector实现类,来筛选Configuration
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
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
*/
String[] excludeName() default {};
}
AutoConfigurationImportSelector
利用ImportSelector的实现类AutoConfigurationImportSelector,加载所需自动配置类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 获取自动配置入口
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
// 获取自动配置入口
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 读取jar包的META-INF/spring.factories文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration的属性值(配置了各个自动配置类名称)
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 进行去重、根据配置过滤不加载的自动配置类
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
通过ImportBeanDefinitionRegistrar和@Import实现
以下以EnableFeignClients为例说明
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] defaultConfiguration() default {};
Class<?>[] clients() default {};
}
EnableFe通过@Import使用了FeignClientsRegistrar,它实现了org.springframework.context.annotation.ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar
public interface ImportBeanDefinitionRegistrar {
/**
* 基于导入的类的注解元数据信息来注册Bean定义
*/
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
同ImportSelector一样,其实现可以通过继承EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口或者单个构件赵晗,来获得以下对象实例
- Environment
- BeanFactory
- ClassLoader
- ResourceLoader
FeignClientsRegistrar
public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, BeanClassLoaderAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 获取EnableFeignClients注解的配置,并进行相应处理
registerDefaultConfiguration(metadata, registry);
// 注册所有FeignClient的Bean对象
registerFeignClients(metadata, registry);
}
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
final Class<?>[] clients = attrs == null ? null
: (Class<?>[]) attrs.get("clients");
if (clients == null || clients.length == 0) {
// 未指定要扫描的有FeignClient类
// 只扫描有FeignClient注解的类
scanner.addIncludeFilter(annotationTypeFilter);
// 根据EnableFeignClients注解配置的范围进行扫描
basePackages = getBasePackages(metadata);
}
else {
final Set<String> clientClasses = new HashSet<>();
basePackages = new HashSet<>();
for (Class<?> clazz : clients) {
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
@Override
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(
new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
}
for (String basePackage : basePackages) {
// 从指定包下查找所有的候选类,并注册为Bean
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(),
"@FeignClient can only be specified on an interface");
Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(
FeignClient.class.getCanonicalName());
String name = getClientName(attributes);
registerClientConfiguration(registry, name,
attributes.get("configuration"));
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}