@SpringBootApplication
class App {
}
// @SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ImportAutoConfiguration
@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)})
@interface SpringBootApplication {
}
// 该注解就是一个普通的配置类标识
@Configuration
@interface SpringBootConfiguration {
}
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
@interface EnableAutoConfiguration {
}
// 该类和EnableAutoConfiguration效果差不多,ImportAutoConfigurationImportSelector也继承AutoConfigurationImportSelector
@Import(ImportAutoConfigurationImportSelector.class)
public @interface ImportAutoConfiguration {
}
/**
* 导入Registrar类,该类主要是导入BasePackages类,保存了需要扫描的包的信息
*
* @see {@link AutoConfigurationPackages.BasePackages}
* @see {@link AutoConfigurationPackages.Registrar#registerBeanDefinitions}
* 该类的作用就是将标@AutoConfigurationPackage注解的类的包名封装成BasePackages对象,然后注册为Bean
* <p/>
* 对于其他外部,如果需要获取到SpringBoot需要自动扫描的包,则可以获取BasePackages这个Bean
* @see {@link AutoConfigurationPackages#get}
* BeanName固定为AutoConfigurationPackages.class.getName
*/
@Import(AutoConfigurationPackages.Registrar.class)
@interface AutoConfigurationPackage {
}
// 自动配置标注了@AutoConfigurationPackage类作为需要扫描的包名
class AutoConfigurationPackages {
private static final String BEAN = AutoConfigurationPackages.class.getName();
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 注册BasePackages的Bean对象,保存了标注@AutoConfigurationPackage注解的类对应的包名
AutoConfigurationPackages.register(registry, new PackageImport(metadata).getPackageName());
}
// 确定导入包的信息
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
// 是否存在BasePackages的Bean对象
public static boolean has(BeanFactory beanFactory) {
return beanFactory.containsBean(BEAN) && !AutoConfigurationPackages.get(beanFactory).isEmpty();
}
// 获取需要扫描的包对应的Bean对象
public static List<String> get(BeanFactory beanFactory) {
try {
return beanFactory.getBean(BEAN, BasePackages.class).get();
} catch (NoSuchBeanDefinitionException ex) {
throw new IllegalStateException("Unable to retrieve @EnableAutoConfiguration base packages");
}
}
// 注册BasePackages的Bean对象,保存了标注@AutoConfigurationPackage注解的类对应的包名
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
// 如果容器中包含"AutoConfigurationPackages" => BasePackages这个Bean
if (registry.containsBeanDefinition(BEAN)) {
// 获取该Bean的BeanDefinition
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
// 添加构造参数
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
// 将构造函数参数中的需要扫描的包名与给定的包名进行合并
String[] packages = AutoConfigurationPackages.addBasePackages(constructorArguments, packageNames);
// 重新添加进去
constructorArguments.addIndexedArgumentValue(0, packages);
return;
}
// 如果不存在BasePackagesBean,创建一个BasePackages的Bean对象
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
// 添加构造参数
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册Bean
registry.registerBeanDefinition(BEAN, beanDefinition);
}
// 将构造函数参数中的需要扫描的包名与给定的包名进行合并
private static String[] addBasePackages(ConstructorArgumentValues constructorArguments, String[] packageNames) {
String[] existing = (String[]) constructorArguments.getIndexedArgumentValue(0, String[].class).getValue();
Set<String> merged = new LinkedHashSet<>();
merged.addAll(Arrays.asList(existing));
merged.addAll(Arrays.asList(packageNames));
return StringUtils.toStringArray(merged);
}
// 保存标注了@AutoConfigurationPackage类的包名
public static final class PackageImport {
// 保存标注了@AutoConfigurationPackage类的包名
private final String packageName;
// 注解的元信息
public PackageImport(AnnotationMetadata metadata) {
// 获取到标注注解的类对应的类名
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
}
public String getPackageName() {
return this.packageName;
}
}
// 保存所有需要扫描的包名
// 该对象会作为Spring中的Bean对象
public static final class BasePackages {
// 需要扫描的包名,该字段是通过beanDefinition.getConstructorArgumentValues()通过构造参数传递的
private final List<String> packages;
public BasePackages(String... names) {
List<String> packages = new ArrayList<>();
// 遍历所有的包名
for (String name : names) {
// 保存这些需要扫描的包名
packages.add(name);
}
this.packages = packages;
}
List<String> get() {
return this.packages;
}
}
}
// 该类是一个延迟导入的类,通过@EnableAutoConfiguration注解导入的,该类会处理spring.factories中的配置类
class AutoConfigurationImportSelector implements DeferredImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 是否开启了自动导入功能,默认开启
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
// 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
// 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
// AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
// 并将properties封装成PropertiesAutoConfigurationMetadata对象
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
// 获取所有符合条件的需要自动导入的配置类,以及需要排除的配置类封装成自动导入条目对象返回
AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
// 返回所有符合条件的配置类
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
/**
* 获取所有符合条件的需要自动导入的配置类,以及需要排除的配置类封装成自动导入条目对象返回
* <pre>
* 步骤:
* 1. 检查自动导入功能是否开启,如果开启了接下一步(key: spring.boot.enableautoconfiguration)
* 2. 从spring.factories中获取EnableAutoConfiguration的key对应所有类的名称
* </pre>
*
* @param autoConfigurationMetadata // 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
* // 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
* // 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
* // AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
* // 并将properties封装成PropertiesAutoConfigurationMetadata对象
* 并将properties封装成PropertiesAutoConfigurationMetadata对象
* @param annotationMetadata 标注@EnableAutoConfiguration注解所在的类的元数据
* @return 所有自动导入的条目信息
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
// 是否开启了自动导入功能,默认开启
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取@EnableAutoConfiguration的属性信息
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 从spring.factories中获取EnableAutoConfiguration的key对应所有类的名称
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 删除重复的配置,就是将List使用Set去重
configurations = this.removeDuplicates(configurations);
// 获取需要排除的类
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 校验排除的类是否是一个正确的类,是在spring.factories中存在的类,如果不存在,抛出异常
this.checkExcludedClasses(configurations, exclusions);
// 从所有的配置类中删除要排除的类
configurations.removeAll(exclusions);
// 从spring.factories文件中加载AutoConfigurationImportFilter类型的实现类对自己装配的类进行过滤
// 返回过滤后的配置类集合
configurations = this.filter(configurations, autoConfigurationMetadata);
// 从spring.factories文件中加载AutoConfigurationImportListener类型的实现类
// 并触发这些监听器的onAutoConfigurationImportEvent方法
this.fireAutoConfigurationImportEvents(configurations, exclusions);
// 将所有需要导入的配置类以及需要排除的配置类封装成自动导入条目对象返回
return new AutoConfigurationEntry(configurations, exclusions);
}
// 从spring.factories文件中加载AutoConfigurationImportListener类型的实现类
// 并触发这些监听器的onAutoConfigurationImportEvent方法
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
// 从spring.factories文件中加载AutoConfigurationImportListener类型的实现类
List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();
// 如果存在监听器
if (!listeners.isEmpty()) {
// 发布一个自动导入配置的事件,将当前类,所有符合条件的配置类,以及需要排除的类封装
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
// 遍历所有的监听器
for (AutoConfigurationImportListener listener : listeners) {
// 执行这些Aware回调方法
this.invokeAwareMethods(listener);
// 回调监听器的onAutoConfigurationImportEvent方法
listener.onAutoConfigurationImportEvent(event);
}
}
}
// 执行对象的Aware接口方法
private void invokeAwareMethods(Object instance) {
if (instance instanceof Aware) {
if (instance instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) instance).setBeanClassLoader(this.beanClassLoader);
}
if (instance instanceof BeanFactoryAware) {
((BeanFactoryAware) instance).setBeanFactory(this.beanFactory);
}
if (instance instanceof EnvironmentAware) {
((EnvironmentAware) instance).setEnvironment(this.environment);
}
if (instance instanceof ResourceLoaderAware) {
((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader);
}
}
}
// 从spring.factories文件中加载AutoConfigurationImportListener类型的实现类
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
}
// 从spring.factories文件中加载AutoConfigurationImportFilter类型的实现类
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
// 从spring.factories文件中加载AutoConfigurationImportFilter类型的实现类对自己装配的类进行过滤
// 返回过滤后的配置类集合
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
// 从spring.factories文件中加载AutoConfigurationImportFilter类型的实现类
List<AutoConfigurationImportFilter> filters = this.getAutoConfigurationImportFilters();
// 遍历所有的过滤器
for (AutoConfigurationImportFilter filter : filters) {
// 执行filter的Aware方法
// BeanClassLoaderAware,BeanFactoryAware,EnvironmentAware,ResourceLoaderAware
this.invokeAwareMethods(filter);
// 调用filter的过滤方法,返回一个对应这所有候选配置类数组是否被排除的数组,一一对应
// 这里就是FilteringSpringBootCondition条件过滤器
// 处理ConditionalOnBean,ConditionalOnSingleCandidate,ConditionalOnClass,ConditionalOnMissingClass,ConditionalOnWebApplication这些注解
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
// 遍历这个对每一个类匹配的结果
for (int i = 0; i < match.length; i++) {
// 如果匹配失败
if (!match[i]) {
// 标识当前配置类需要被跳过
skip[i] = true;
// 将候选的类置空,因为这是一个循环,还有多个AutoConfigurationImportFilter要进行处理
candidates[i] = null;
// 标识存在需要跳过的类
skipped = true;
}
}
}
// 如果不存在被跳过的类,那么直接返回传递过来的配置类
if (!skipped) {
return configurations;
}
// 有需要被跳过的类
// 创建一个用于保存最终需要解析的配置类结果
List<String> result = new ArrayList<>(candidates.length);
// 遍历所有的配置类
for (int i = 0; i < candidates.length; i++) {
// 如果不需要被跳过
if (!skip[i]) {
// 保存配置
result.add(candidates[i]);
}
}
// 返回没有被跳过的类
return new ArrayList<>(result);
}
// 校验排除的类是否是一个正确的类,是在spring.factories中存在的类,如果不存在,抛出异常
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
List<String> invalidExcludes = new ArrayList<>(exclusions.size());
// 遍历已经要排除的类
for (String exclusion : exclusions) {
// 如果该类确实存在,并且在需要加载的所有配置类中不存在该排序的类
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
// 那么,该类表示无效的排除类
invalidExcludes.add(exclusion);
}
}
// 具有无效的排除类,抛出异常
if (!invalidExcludes.isEmpty()) {
this.handleInvalidExcludes(invalidExcludes);
}
}
// 获取需要排除的类
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
// 获取@EnableAutoConfiguration属性exclude的值
excluded.addAll(asList(attributes, "exclude"));
// 获取@EnableAutoConfiguration属性excludeName的值
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
// 获取环境配置中的spring.autoconfigure.exclude的属性值这个配置的值表示忽略哪些文件
excluded.addAll(this.getExcludeAutoConfigurationsProperty());
return excluded;
}
// 获取环境配置中的spring.autoconfigure.exclude的属性值这个配置的值表示忽略哪些文件
private List<String> getExcludeAutoConfigurationsProperty() {
if (getEnvironment() instanceof ConfigurableEnvironment) {
Binder binder = Binder.get(getEnvironment());
// 获取环境对象中spring.autoconfigure.exclude的属性,并绑定到字符串数组中返回
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList).orElse(Collections.emptyList());
}
// 获取环境配置spring.autoconfigure.exclude的值
String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
}
// 从spring.factories中获取EnableAutoConfiguration的key对应所有类的名称
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 从spring.factories中获取EnableAutoConfiguration的key对应所有类的名称
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, getBeanClassLoader());
return configurations;
}
// 是否开启了自动导入功能
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
// 获取配置属性为"spring.boot.enableautoconfiguration"的值,默认为true
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
// 自动配置的元数据加载器
public class AutoConfigurationMetadataLoader {
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
// 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
// 并将properties封装成PropertiesAutoConfigurationMetadata对象
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return AutoConfigurationMetadataLoader.loadMetadata(classLoader, PATH);
}
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
// 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
// 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
// AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
// 并将properties封装成PropertiesAutoConfigurationMetadata对象
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件
Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path) : ClassLoader.getSystemResources(path);
// 保存META-INF/spring-autoconfigure-metadata.properties中的所有配置
Properties properties = new Properties();
// 遍历所有的文件
while (urls.hasMoreElements()) {
// 将该配置类中所有的键值对保存到properties中
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
// 将所有属性配置封装为AutoConfigurationMetadata对象
return AutoConfigurationMetadataLoader.loadMetadata(properties) {
// 该对象就是从properties中获取对应的属性值
return new PropertiesAutoConfigurationMetadata(properties);
}
}
}
// 延迟导入处理类的分组
public static class AutoConfigurationGroup implements DeferredImportSelector.Group {
// 所有需要导入的配置类=>导入的来源类的映射关系
private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();
// 所有需要自动导入的配置类条目信息,每一个AutoConfigurationEntry对象包含了这个模块对应所有需要导入的类
private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();
// 开始处理延迟导入的Bean操作
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
// 将AutoConfigurationImportSelector类解析好的AutoConfigurationEntry获取出来
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
// 保存到当前AutoConfigurationGroup类中
this.autoConfigurationEntries.add(autoConfigurationEntry);
// 遍历所有需要导入的配置类
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
// 保存所有需要保存的配置类
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
// 获取需要导入的所有类
// 将配置类转换为Entry类型,key为: 导入该配置类的来源类 ,值为: 该配置类名称
public Iterable<Entry> selectImports() {
// 如果没有需要自动导入的条目
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
// 过滤所有条目中需要排除的类
Set<String> allExclusions = this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
// 获取所有条目中需要导入的类
Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
// 将所有导入的类中删除需要排除的类
processedConfigurations.removeAll(allExclusions);
// 将所有配置类的优先级排序序之后
return this.sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata())
.stream()
// 将配置类转换为Entry类型,key为: 导入该配置类的来源类 ,值为: 该配置类名称
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
// 返回的是PropertiesAutoConfigurationMetadata
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
// 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
// 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
// AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
// 并将properties封装成PropertiesAutoConfigurationMetadata对象
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
if (this.autoConfigurationMetadata == null) {
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到autoConfigurationMetadata一个properties中
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
}
return this.autoConfigurationMetadata;
}
// 对说中配置类进行排序,最终得到所有配置类的加载顺序
private List<String> sortAutoConfigurations(Set<String> classNames, AutoConfigurationMetadata autoConfigurationMetadata) {
// 获取自动配置类的排序器
AutoConfigurationSorter sorter = new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata);
// 根据优先级排序,Order接口以及@AutoConfigureBefore @AutoConfigureAfter注解
// 最终得到所有配置类的加载顺序
List<String> result = sorter.getInPriorityOrder(classNames);
return result;
}
// 获取"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"对应的元数据加载的工厂类的Bean
private MetadataReaderFactory getMetadataReaderFactory() {
// 获取"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"对应的元数据加载的工厂类的Bean
return this.beanFactory.getBean(SharedMetadataReaderFactoryContextInitializer.BEAN_NAME, MetadataReaderFactory.class);
}
}
// 自动配置类的排序器
class AutoConfigurationSorter {
// 类元数据的解析工厂
private final MetadataReaderFactory metadataReaderFactory;
// 自动配置类的属性配置元数据对象
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
// 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
// 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
// AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
// 并将properties封装成PropertiesAutoConfigurationMetadata对象
private final AutoConfigurationMetadata autoConfigurationMetadata;
// 根据优先级排序,Order接口以及@AutoConfigureBefore @AutoConfigureAfter注解
// 最终得到所有配置类的加载顺序
public List<String> getInPriorityOrder(Collection<String> classNames) {
// 所有需要导入的类名,所有的META-INF/spring-autoconfigure-metadata.properties配置文件的数据对象包装成自动配置的类中AutoConfigurationClasses
AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory, this.autoConfigurationMetadata, classNames);
List<String> orderedClassNames = new ArrayList<>(classNames);
// 根据自然顺序进行排序
Collections.sort(orderedClassNames);
// 再根据Order接口进行排序
orderedClassNames.sort((o1, o2) -> {
int i1 = classes.get(o1).getOrder();
int i2 = classes.get(o2).getOrder();
return Integer.compare(i1, i2);
});
// 根据注解排序 @AutoConfigureBefore @AutoConfigureAfter
orderedClassNames = this.sortByAnnotation(classes, orderedClassNames);
return orderedClassNames;
}
// 根据注解排序 @AutoConfigureBefore @AutoConfigureAfter
private List<String> sortByAnnotation(AutoConfigurationClasses classes, List<String> classNames) {
// 所有需要排序的类
List<String> toSort = new ArrayList<>(classNames);
// 获取所有需要自动装配的配置类,包含了与给定的配置类存在加载关系的类
toSort.addAll(classes.getAllNames());
// 已经拍好序类
Set<String> sorted = new LinkedHashSet<>();
// 已经处理过的类
Set<String> processing = new LinkedHashSet<>();
// 如果有需要排序的类
while (!toSort.isEmpty()) {
// 使用@AfterAnnotation进行排序
this.doSortByAfterAnnotation(classes, toSort, sorted, processing, null);
}
// 从已排好序的配置类中,删除在classNames中不存在的配置类
// 因为我们只需要classNames中的元素
sorted.retainAll(classNames);
// 返回排好序的结果
return new ArrayList<>(sorted);
}
//
/**
* 使用@AutoConfigureAfter注解进行排序,为什么没有按照@AutoConfigureBefore注解排序方法呢?
* 因为{@link AutoConfigurationClasses#getClassesRequestedAfter(String)}中,统一时候后置进行排序
* <pre>
* 什么意思呢?
* 如果我在你前面,那么,你就在我后面,因此,按照这种套路,就可以找到所有标记了我在他前面的类
* 这样,就能拿到我后面的所有类,这样,从第一个类开始,就可以按照先后顺序排到最后一个
* </pre>
*
* @param classes 需要排序的所有的类
* @param toSort 需要排序的类
* @param sorted 已经排好序的类
* @param processing 正在进行排序的类
* @param current 当前正在排序的类
*/
private void doSortByAfterAnnotation(AutoConfigurationClasses classes, List<String> toSort, Set<String> sorted, Set<String> processing, String current) {
// 如果当前排序的类为空,表示第一次使用这个类,取出第一个类开始排序
// 如果不为空,表示是通过递归处理的
if (current == null) {
current = toSort.remove(0);
}
// 保存正在处理的类
processing.add(current);
// 获取需要在当前类之后加载的类
Set<String> classesRequestedAfter = classes.getClassesRequestedAfter(current);
for (String after : classesRequestedAfter) {
// 如果未拍好序,并且该类需要排序
if (!sorted.contains(after) && toSort.contains(after)) {
// 递归排序,因为要一层一层排
// 例如: a要在b后面,a还要在c后面,b又要在c后面,这种顺序逻辑关系
// 最终得到 a在b后面,a也在c后面
this.doSortByAfterAnnotation(classes, toSort, sorted, processing, after);
}
}
// 该类存储完毕,移除该类
processing.remove(current);
// 表示该类已经排好序了
sorted.add(current);
}
// 所有自动配置的类信息
public static class AutoConfigurationClasses {
// 保存所有需要自动装配的配置类,包含了与给定的配置类存在加载关系的类
private final Map<String, AutoConfigurationClass> classes = new HashMap<>();
/**
* @param metadataReaderFactory 解析类元数据的工厂
* @param autoConfigurationMetadata // 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
* // 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
* // 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
* // AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
* // 并将properties封装成PropertiesAutoConfigurationMetadata对象
* @param classNames 所有需要处理的配置类
*/
public AutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory, AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames) {
// 将所有符合装配条件的配置类通过META-INF/spring-autoconfigure-metadata.properties或者@AutoConfigureOrder,@AutoConfigureAfter,@AutoConfigureBefore注解描述的关系
// 将这些存在关系的类也进行保存,到时候也需要加载
this.addToClasses(metadataReaderFactory, autoConfigurationMetadata, classNames, true);
}
/**
* 将所有符合装配条件的配置类通过META-INF/spring-autoconfigure-metadata.properties或者@AutoConfigureOrder,@AutoConfigureAfter,@AutoConfigureBefore注解描述的关系
* 将这些存在关系的类也进行保存,到时候也需要加载
*
* @param metadataReaderFactory 解析类元数据的工厂
* @param autoConfigurationMetadata // 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
* // 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一
* // 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
* // AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
* // 并将properties封装成PropertiesAutoConfigurationMetadata对象
* @param classNames 所有需要处理的配置类
* @param required 是否必须加载
*/
private void addToClasses(MetadataReaderFactory metadataReaderFactory, AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames, boolean required) {
// 遍历所有的类名
for (String className : classNames) {
// 如果该classes没有包含,表示没有处理过该类
if (!this.classes.containsKey(className)) {
// 创建单个自动配置类的信息,比如,要在那个类之后加载,之前加载等等
AutoConfigurationClass autoConfigurationClass = new AutoConfigurationClass(className, metadataReaderFactory, autoConfigurationMetadata);
// 该配置类是否可用
// 这个类在META-INF/spring-autoconfigure-metadata.properties中存在,或者可以成功加载这个类
boolean available = autoConfigurationClass.isAvailable();
// 如果必须,或者可用,required: 从构造方法调用的,为true,递归调用的为false
if (required || available) {
// 保存需要自动装配的配置类
this.classes.put(className, autoConfigurationClass);
}
// 配置类可用
if (available) {
// 不断递归添加要在该类之前加载的类
this.addToClasses(metadataReaderFactory, autoConfigurationMetadata, autoConfigurationClass.getBefore(), false);
// 不断递归添加要在该类后加载的类
this.addToClasses(metadataReaderFactory, autoConfigurationMetadata, autoConfigurationClass.getAfter(), false);
}
}
}
}
// 获取所有需要自动装配的配置类,包含了与给定的配置类存在加载关系的类
public Set<String> getAllNames() {
return this.classes.keySet();
}
// 获取指定配置类的自动装配信息,比如,要在那个类之后加载,之前加载等等
public AutoConfigurationClass get(String className) {
return this.classes.get(className);
}
// 需要在该指定类之后加载的类
public Set<String> getClassesRequestedAfter(String className) {
// 获取需要在给定配置类之后加载的类名
Set<String> after = this.get(className).getAfter();
// 获取需要在该指定类之后加载的类
Set<String> classesRequestedAfter = new LinkedHashSet<>(after);
// 遍历所有需要加载的配置类信息
this.classes.forEach((String name, AutoConfigurationClass autoConfigurationClass) -> {
// 获取需要在正在遍历的配置类之前加载的类,如果这些类中包含当前指定的类
// 那么表示指定的类就需要在正在遍历的类后面加载
if (autoConfigurationClass.getBefore().contains(className)) {
// 保存需要在当前指定的类后面加载的类
// 说白了就是className需要在正在遍历的类之前加载,反过来,正在遍历的类需要在指定的当前类之后加载
classesRequestedAfter.add(name);
}
});
// 需要在该指定类之后加载的类
return classesRequestedAfter;
}
}
// 单个自动配置类的信息,比如,要在那个类之后加载,之前加载等等
public static class AutoConfigurationClass {
// 配置类类名
private final String className;
// 解析类的元数据工厂
private final MetadataReaderFactory metadataReaderFactory;
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
// 该配置文件存储着自动配置类的装配条件,该配置文件是对自动配置的优化,这样就不需要获取类中的元数据注解再来决定类如何装配,实际上这些与在类中配置的注解效果是一样的
// 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
// AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
// 并将properties封装成PropertiesAutoConfigurationMetadata对象
private final AutoConfigurationMetadata autoConfigurationMetadata;
// 该配置类className对应的注解元信息
private volatile AnnotationMetadata annotationMetadata;
// 当前配置类在META-INF/spring-autoconfigure-metadata.properties配置的AutoConfigureBefore的类
// 也就是需要在当前类之前进行配置的类
private volatile Set<String> before;
// 当前配置类在META-INF/spring-autoconfigure-metadata.properties配置的AutoConfigureAfter的类
// 也就是需要在当前类之后进行配置的类
private volatile Set<String> after;
public AutoConfigurationClass(String className, MetadataReaderFactory metadataReaderFactory, AutoConfigurationMetadata autoConfigurationMetadata) {
this.className = className;
this.metadataReaderFactory = metadataReaderFactory;
this.autoConfigurationMetadata = autoConfigurationMetadata;
}
// 该配置类是否可用
// 这个类在META-INF/spring-autoconfigure-metadata.properties中存在,或者可以成功加载这个类
public boolean isAvailable() {
try {
// 该类在META-INF/spring-autoconfigure-metadata.properties是否存在配置信息
if (!this.wasProcessed()) {
// 获取该配置类对应的注解元信息,如果能获取到,表示该类存在,加载失败可能没引入这个类
this.getAnnotationMetadata();
}
// 这个类在META-INF/spring-autoconfigure-metadata.properties中存在,或者可以成功加载这个类
return true;
} catch (Exception ex) {
// 该类不存在
return false;
}
}
// 获取当前配置类在META-INF/spring-autoconfigure-metadata.properties配置文件中标识的AutoConfigureBefore对应的类
public Set<String> getBefore() {
if (this.before == null) {
// 所有的META-INF/spring-autoconfigure-metadata.properties配置文件的数据
this.before = (this.wasProcessed() ?
this.autoConfigurationMetadata.getSet(this.className, "AutoConfigureBefore", Collections.emptySet())
// 如果META-INF/spring-autoconfigure-metadata.properties配置文件中不存在,就只能加载类中的注解来获取
// 因为META-INF/spring-autoconfigure-metadata.properties中是对自动配置的优化,不用去解析类的元数据
: this.getAnnotationValue(AutoConfigureBefore.class));
}
return this.before;
}
// 获取当前配置类在META-INF/spring-autoconfigure-metadata.properties配置文件中标识的AutoConfigureAfter对应的类
public Set<String> getAfter() {
if (this.after == null) {
// 所有的META-INF/spring-autoconfigure-metadata.properties配置文件的数据
this.after = (this.wasProcessed() ? this.autoConfigurationMetadata.getSet(this.className, "AutoConfigureAfter", Collections.emptySet())
// 如果META-INF/spring-autoconfigure-metadata.properties配置文件中不存在,就只能加载类中的注解来获取
// 因为META-INF/spring-autoconfigure-metadata.properties中是对自动配置的优化,不用去解析类的元数据
: this.getAnnotationValue(AutoConfigureAfter.class));
}
return this.after;
}
// 获取当前配置类在META-INF/spring-autoconfigure-metadata.properties配置文件中标识的AutoConfigureOrder对应的类
private int getOrder() {
// 该类在META-INF/spring-autoconfigure-metadata.properties是否存在配置信息
if (this.wasProcessed()) {
// 默认Order为0
return this.autoConfigurationMetadata.getInteger(this.className, "AutoConfigureOrder", AutoConfigureOrder.DEFAULT_ORDER);
}
// 该类在META-INF/spring-autoconfigure-metadata.properties不存在配置,就只能加载类中的注解来获取
// 因为META-INF/spring-autoconfigure-metadata.properties中是对自动配置的优化,不用去解析类的元数据
Map<String, Object> attributes = this.getAnnotationMetadata().getAnnotationAttributes(AutoConfigureOrder.class.getName());
// 获取@AutoConfigureOrder注解对应的属性配置,默认值为:0
return (attributes != null) ? (Integer) attributes.get("value") : AutoConfigureOrder.DEFAULT_ORDER;
}
// 该类在META-INF/spring-autoconfigure-metadata.properties是否存在配置信息
private boolean wasProcessed() {
// 该类在META-INF/spring-autoconfigure-metadata.properties中配置了,autoConfigurationMetadata中的properties中存在该类的Key,就表示需要被加载
return (this.autoConfigurationMetadata != null && this.autoConfigurationMetadata.wasProcessed(this.className));
}
/**
* 获取指定注解的属性,包含@AutoConfigureAfter,@AutoConfigureBefore
*
* @param annotation 注解信息,@AutoConfigureAfter,@AutoConfigureBefore
* @return 该注解配置的value和name值
*/
private Set<String> getAnnotationValue(Class<?> annotation) {
// 获取该类的元数据中的指定注解信息
Map<String, Object> attributes = this.getAnnotationMetadata().getAnnotationAttributes(annotation.getName(), true);
// 如果不存在指定注解
if (attributes == null) {
return Collections.emptySet();
}
// 存在指定注解
Set<String> value = new LinkedHashSet<>();
// 保存该注解的value和name值
Collections.addAll(value, (String[]) attributes.get("value"));
Collections.addAll(value, (String[]) attributes.get("name"));
return value;
}
// 获取该配置类对应的注解元信息
private AnnotationMetadata getAnnotationMetadata() {
if (this.annotationMetadata == null) {
// 加载该配置类的元信息
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(this.className);
// 获取该配置类对应的注解元信息
this.annotationMetadata = metadataReader.getAnnotationMetadata();
}
return this.annotationMetadata;
}
}
// 加载所有的META-INF/spring-autoconfigure-metadata.properties配置文件,将全部保存到一个properties中
// 该配置文件存储着自动配置类的装配条件,这些与在类中配置的注解效果是一样的
// 例如: ConditionalOnSingleCandidate,ConditionalOnClass,AutoConfigureAfter
// AutoConfigureOrder,ConditionalOnBean,AutoConfigureBefore
// 并将properties封装成PropertiesAutoConfigurationMetadata对象
public static class PropertiesAutoConfigurationMetadata implements AutoConfigurationMetadata {
// 保存这所有META-INF/spring-autoconfigure-metadata.properties的配置信息
private final Properties properties;
public PropertiesAutoConfigurationMetadata(Properties properties) {
this.properties = properties;
}
// 该类在META-INF/spring-autoconfigure-metadata.properties配置文件是否存在
public boolean wasProcessed(String className) {
return this.properties.containsKey(className);
}
// 获取int类型的值
public Integer getInteger(String className, String key) {
return getInteger(className, key, null);
}
public Integer getInteger(String className, String key, Integer defaultValue) {
String value = get(className, key);
return (value != null) ? Integer.valueOf(value) : defaultValue;
}
// 获取set类型的值
public Set<String> getSet(String className, String key) {
return getSet(className, key, null);
}
public Set<String> getSet(String className, String key, Set<String> defaultValue) {
String value = get(className, key);
return (value != null) ? StringUtils.commaDelimitedListToSet(value) : defaultValue;
}
// 获取String类型的值
public String get(String className, String key) {
return get(className, key, null);
}
public String get(String className, String key, String defaultValue) {
String value = this.properties.getProperty(className + "." + key);
return (value != null) ? value : defaultValue;
}
}
}
}
/**
* 处理@ImportAutoConfiguration注解的类
*
* @see {@link AutoConfigurationImportSelector}
*/
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
// 可以解析的注解名
private static final Set<String> ANNOTATION_NAMES;
// 该类会处理@ImportAutoConfiguration和测试包的test.ImportAutoConfiguration注解
static {
Set<String> names = new LinkedHashSet<>();
// @ImportAutoConfiguration
names.add(ImportAutoConfiguration.class.getName());
// 测试包的@ImportAutoConfiguration注解
names.add("org.springframework.boot.autoconfigure.test.ImportAutoConfiguration");
ANNOTATION_NAMES = Collections.unmodifiableSet(names);
}
/**
* 确定需要导入的类
*
* @param metadata 标注@ImportAutoConfiguration类的元信息
*/
public Set<Object> determineImports(AnnotationMetadata metadata) {
// 获取候选的配置类,该类重写了默认的从spring.factories获取配置,而是从@ImportAutoConfiguration注解中获取需要导入的类
List<String> candidateConfigurations = this.getCandidateConfigurations(metadata, null);
Set<String> result = new LinkedHashSet<>(candidateConfigurations);
// 获取需要排除的类
Set<String> exclusions = this.getExclusions(metadata, null);
// 在获取的所有候选配置类中,删除要排除的类
result.removeAll(exclusions);
// 返回所有符合条件的配置类
return Collections.unmodifiableSet(result);
}
// 该类不处理
@Override
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
return null;
}
/**
* 获取候选的配置类,该类重写了默认的从spring.factories获取配置
*
* @param metadata 标注@ImportAutoConfiguration类的元信息
* @param attributes 注解属性信息,这个为空,因为当前类覆盖了父类的{@link ImportAutoConfigurationImportSelector#getAttributes}方法
* @return 所有符合条件的配置类
*/
@Override
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> candidates = new ArrayList<>();
// 收集入口配置类中所有的@ImportAutoConfiguration注解信息,包括注解中的,父类的
// Key为出现@ImportAutoConfiguration的类的Class,Value为@ImportAutoConfiguration注解信息
// 用List作为Value是同时为了处理org.springframework.boot.autoconfigure.test.ImportAutoConfiguration注解
Map<Class<?>, List<Annotation>> annotations = this.getAnnotations(metadata);
// 遍历所有收集到了@ImportAutoConfiguration注解信息
annotations.forEach((source, sourceAnnotations) -> this.collectCandidateConfigurations(source, sourceAnnotations, candidates));
// 返回所有需要加载的配置类
return candidates;
}
/**
* 收集@ImportAutoConfiguration注解中需要导入的配置类信息
*
* @see {@link ImportAutoConfigurationImportSelector#getConfigurationsForAnnotation}
*/
private void collectCandidateConfigurations(Class<?> source, List<Annotation> annotations, List<String> candidates) {
// 遍历该配置类中存在的所有@ImportAutoConfiguration注解
// 用List作为Value是同时为了处理org.springframework.boot.autoconfigure.test.@ImportAutoConfiguration注解
// 因为这个配置类可以同时配置这两个注解
for (Annotation annotation : annotations) {
// 从@ImportAutoConfiguration注解信息中,获取需要导入的配置类
Collection<String> forAnnotation = this.getConfigurationsForAnnotation(source, annotation);
// 保存所有注解中导入的所有类的信息
candidates.addAll(forAnnotation);
}
}
/**
* 从@ImportAutoConfiguration注解信息中,获取需要导入的配置类
* <pre>
* 1. 如果@ImportAutoConfiguration标注了需要导入的类,那么导入的那个类才是配置类
* 2. 如果@ImportAutoConfiguration没有标注需要导入的类,只有一个注解
* 那么会加载标注该注解的类作为Key,从spring.factories获取对应的配置信息
* 例如:
* @ImportAutoConfiguration
* class A{}
* 那么,会自动从spring.factories中找a的全类名对应的配置类信息
* 2.1 再举个例子: 在自己项目中,创建一个org.springframework.boot.autoconfigure.EnableAutoConfiguration类
* 在类中标注@ImportAutoConfiguration注解,并将EnableAutoConfiguration类设置为SpringApplication的配置类
* 那么,与@EnableAutoConfiguration的作用几乎一样,但是一般不会这么做
* </pre>
*
* @param source 标注@ImportAutoConfiguration注解的为了或者注解
* @param annotation @ImportAutoConfiguration注解信息
* @return 所有配置类信息
*/
private Collection<String> getConfigurationsForAnnotation(Class<?> source, Annotation annotation) {
// 获取@ImportAutoConfiguration注解的信息
String[] classes = (String[]) AnnotationUtils.getAnnotationAttributes(annotation, true).get("classes");
// 如果配置了导入的配置类,那么直接返回这个配置类
if (classes.length > 0) {
return Arrays.asList(classes);
}
// 如果没有配置,那么会加载标注该注解的类作为Key,从spring.factories获取对应的配置信息
return loadFactoryNames(source);
}
// 根据指定类型名从spring.factories中获取该key对应的配置类信息
protected Collection<String> loadFactoryNames(Class<?> source) {
return SpringFactoriesLoader.loadFactoryNames(source, getClass().getClassLoader());
}
// 获取需要排除的类
@Override
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 所有需要的排除的类
Set<String> exclusions = new LinkedHashSet<>();
// 解析标注了@ImportAutoConfiguration注解的类(入口配置类)
Class<?> source = ClassUtils.resolveClassName(metadata.getClassName(), null);
// 遍历当前类所有的支持处理的注解
for (String annotationName : ANNOTATION_NAMES) {
// 获取到注解的属性信息
AnnotationAttributes merged = AnnotatedElementUtils.getMergedAnnotationAttributes(source, annotationName);
// 获取注解中需要排除的类
Class<?>[] exclude = (merged != null) ? merged.getClassArray("exclude") : null;
// 如果配置了
if (exclude != null) {
// 保存需要排除的类名
for (Class<?> excludeClass : exclude) {
exclusions.add(excludeClass.getName());
}
}
}
// 再解析入口配置类中所有的@ImportAutoConfiguration注解信息,包括注解中的,父类的
// 获取收集到的所有@ImportAutoConfiguration信息
List<Annotation>[] values = this.getAnnotations(metadata).values();
for (List<Annotation> annotations : values) {
// 遍历所有的@ImportAutoConfiguration注解
for (Annotation annotation : annotations) {
// 获取该注解的排除类属性
String[] exclude = (String[]) AnnotationUtils.getAnnotationAttributes(annotation, true).get("exclude");
// 如果不为空
if (!ObjectUtils.isEmpty(exclude)) {
// 保存需要排除的类
exclusions.addAll(Arrays.asList(exclude));
}
}
}
return exclusions;
}
// 收集入口配置类中所有的@ImportAutoConfiguration注解信息,包括注解中的,父类的
protected final Map<Class<?>, List<Annotation>> getAnnotations(AnnotationMetadata metadata) {
MultiValueMap<Class<?>, Annotation> annotations = new LinkedMultiValueMap<>();
// 解析标注了@ImportAutoConfiguration类的类名
Class<?> source = ClassUtils.resolveClassName(metadata.getClassName(), null);
// 收集入口配置类中所有的@ImportAutoConfiguration注解信息,包括注解中的,父类的
this.collectAnnotations(source, annotations, new HashSet<>());
return Collections.unmodifiableMap(annotations);
}
/**
* 收集入口配置类中所有的@ImportAutoConfiguration注解信息,包括注解中的,父类的
*
* @param source 需要收集@ImportAutoConfiguration注解的类的信息
* @param annotations 需要保存该source中的所有@ImportAutoConfiguration注解的类
* @param seen 已经处理过的类
*/
private void collectAnnotations(Class<?> source, MultiValueMap<Class<?>, Annotation> annotations, HashSet<Class<?>> seen) {
// 如果需要收集注解的类不为空,并且没有处理过
if (source != null && seen.add(source)) {
// 获取类中所有的注解
for (Annotation annotation : source.getDeclaredAnnotations()) {
// 如果不是java.lang.annotation包中的注解
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
// 如果存在@ImportAutoConfiguration注解
if (ANNOTATION_NAMES.contains(annotation.annotationType().getName())) {
// 保存该类与该@ImportAutoConfiguration注解的映射关系
annotations.add(source, annotation);
}
// 再根据当前注解类型再去找注解中的@ImportAutoConfiguration注解信息
this.collectAnnotations(annotation.annotationType(), annotations, seen);
}
}
// 找完了当前类,继续收集父类的@ImportAutoConfiguration注解信息
this.collectAnnotations(source.getSuperclass(), annotations, seen);
}
}
// 在AutoConfigurationImportSelector之前执行
@Override
public int getOrder() {
return super.getOrder() - 1;
}
// 处理用户排除的无效的类
@Override
protected void handleInvalidExcludes(List<String> invalidExcludes) {
}
}
相关推荐
SpringBoot中 @Import 和 @ImportAutoConfiguration 的区别是什么?
1、@ImportAutoConfiguration 和 @EnableAutoConfiguration 内部都依赖了 @Import 注解,都支持把各个依赖包的 resources 目录下 MATE-INFO 目录下的 spring.factories 文件中配置的自动配置类加载到Spring容器中。1、@Import 注解只能通过 value 属性值进行导入,由于 @Import 注解的value只接受 Class 类型,意味着所导入的类必须在当前模块或所依赖的下游模块中,灵活性有限制。
java.lang.IllegalStateException: Unable to retrieve @EnableAutoConfiguration base packages
错误:java.lang.IllegalStateException: Unable to retrieve @EnableAutoConfiguration base packages 在做单元测试的时候,出现这个错误,直接上代码和解决方案 这个是出错的代码,目标想用datajpatest测试Elasticsearch,由于datajpatest原生并不包含Elasticsearch的启动项所以需要手动添加 @DataJpaTest( includeFilters = @ComponentScan.Fil
VSCode下载、安装+C语言环境配置(超详细)
ps:我的更改部分:"D:/BaiduNetdiskDownload/x86_64-8.1.0-release-win32-seh-rt_v6-rev0/mingw64。③ 找到【系统变量】中的【Path】变量 ---- 双击打开后,将刚刚复制的地址添加进去 ---- 点击【确定】;① 双击【此电脑】---- 点击【属性】---- 进入到下面这个界面,单击【高级系统设置】;② 进入到 系统属性界面 ---- 点击【环境变量】,进入环境变量页面;并进行安装,安装成功后,打开VSCode;
@EnableAutoConfiguration和@ImportAutoConfiguration的区别
是加载所有的自动配置类, 这其中包含了缓存, JPA等功能的自动配置类为key的自动配置类而加载自定义属性classes中的配置类集合或者某一独立功能的自动配置类集合(如因此的相比较而言, 更加灵活, 并且实现了对自动配置的范围定制。
PyTorch实战:用FGSM攻击MNIST分类器(附可视化对比)
本文通过PyTorch实战演示了如何使用FGSM对抗攻击方法攻击MNIST手写数字分类器。文章详细解析了FGSM攻击原理,提供了从环境搭建、模型准备到攻击实施、可视化对比的完整代码实战流程,并探讨了对抗样本的生成与模型鲁棒性评估。
Tesla V100 在 Windows 下的驱动选择与模式切换实战
本文详细解析了Tesla V100专业计算卡在Windows系统下的驱动安装与模式切换实战。针对设备管理器识别但任务管理器“隐身”的常见问题,文章指出其默认TCC模式为纯计算设计,并指导用户正确选择数据中心或GRID驱动。核心在于通过注册表修改或驱动选择,在高效的TCC模式与便于监控的WDDM模式间切换,同时提供了nvidia-smi命令行监控与AI框架测试等稳定使用方案。
【源码解析】自动配置的这些细节不知道,别说你会 springboot
spring-boot 相对于 spring,很重要的一个特点就是自动配置,使约定大于配置思想成功落地。xxx-spring-boot-starter 一系列引导器能够开箱即用,或者只需要很少的配置(对于初学人员)就是因为已做了默认的自动配置。 自动配置在一开始就初始化了一些配置,同时提供修改配置的入口。 整体结构 spring-boot-autoconfigure 包是 spring-boot-...
【异常】飞书OpenClaw机器人 HTTP 401: Invalid Authentication 报错排查与解决方案
HTTP 401 是HTTP协议标准定义的未授权(Unauthorized)状态码,核心含义为请求方身份认证无效,服务端拒绝执行本次请求。飞书开放平台服务端对自建机器人的全链路鉴权校验失败。无论是机器人接收飞书事件推送的上行请求,还是机器人主动调用飞书开放平台API的下行请求,只要身份凭证无效、鉴权逻辑校验不通过,飞书服务端就会返回该报错,并最终透传到飞书客户端会话窗口中。
【源码解析】自动配置的这些细节都不知道,别说你会 springboot
spring-boot 相对于 spring,很重要的一个特点就是自动配置,使约定大于配置思想成功落地。xxx-spring-boot-starter 一系列引导器能够开箱即用,或者只需要很少的配置(对于初学人员)就是因为已做了默认的自动配置。 自动配置在一开始就初始化了一些配置,同时提供修改配置的入口。 整体结构 spring-boot-autoconfigure 包是 spring-bo...
机器学习实战——疫情数据分析与预测
机器学习如何做到疫情可视化——疫情数据分析与预测实战 本文将带领大家爬取11个国家以及中国31个省(自治区、直辖市)在2022.0101-2022.06.19的新冠疫情数据。并且采用机器学习模型对2022.6.20-2022.6.30每一天的全国确诊人数、死亡人数、治愈人数进行预测,**做出疫情可视化图形并且求出最终的相关系数R2!...
用「OpenClaw」打造新媒体运营神器:小红书/公众号全自动选题→创作→排版→发布全流程
对于新媒体运营的从业者来说,AI不是要取代运营人员,而是把他们从繁琐的重复劳动中解放出来,专注于更核心的内容策略、用户运营、品牌建设,这才是AI在传统行业落地的真正价值。这是最终输出可发布内容的核心智能体,我们通过「OpenClaw」的Prompt工程,结合不同平台的排版规范,实现了一键生成符合要求的排版,完全替代人工重复劳动。这套系统的落地,不是技术的炫技,而是真正用AI解决了新媒体运营的核心痛点:用自动化替代重复的人工劳动,用数据决策替代经验主义,用全闭环执行替代纸上谈兵的建议。
springboot 注解_Spring Boot – 注解
一场寂寞凭谁诉。算前言,总轻负。概述spring boot注解大部分是在org.springframework.boot.autoconfigure和org.springframework.boot.autoconfigure.condition包中。让我们来了解一些常用的spring boot注解以及它们背后的工作原理。@SpringBootApplicationSpring boot主要功能是...
20 Embedding 与向量检索:语义为什么能变成距离
Embedding 是 RAG 语义检索的数学基础。本文用工程视角讲清文本如何变成向量,为什么语义相近会表现为距离相近,Top-K 检索如何工作,以及在模型选择、同模型约束、精确匹配和召回评估上的常见坑。
SpringBoot自动装配原理与实践指南
自动装配是Spring框架实现依赖注入的核心机制,通过@Conditional条件注解和约定优于配置的原则,实现了组件的智能加载。在SpringBoot中,自动装配技术通过starter模块将这一理念发挥到极致,开发者只需引入相关依赖即可获得开箱即用的功能体验。其底层基于ImportSelector机制和条件评估系统,能够根据类路径、配置属性等运行时状态动态决定Bean的注册行为。这种设计显著提升了开发效率,在微服务架构、企业级应用开发等场景中广泛应用。通过合理使用@Autowired注解和自定义start
【Burp入门第二篇】Chrome配置BurpSuite代理教程
1、配置Burp代理为127.0.0.1:80802、扩展商店添加插件switchyomega,修改服务器和端口为下图:3、打开代理,选择刚才添加的代理
文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况
主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。
Spring boot框架
Spring boot框架
复分析 阿尔福斯(Ahlfors) 第三版答案 英文
答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案
@ImportAutoConfiguration 和 @EnableAutoConfiguration 注解的区别
Spring Boot中提供了一系列的注解比如@ImportAutoConfiguration和@EnableAutoConfiguration,它们最终都组合了@Import注解。 从根本上来说,@ImportAutoConfiguration是@Import的增强,限制了它使用的特定范围。 使用@EnableAutoConfiguration时会扫描整个类路径下,包括依赖引入的jar包所有的自动配置类(被注解了@Configuration的类),尝试进行自动配置。 而@ImportAutoConf
Statistics and Machine Learning Toolbox
Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具
怀旧版电脑GBC模拟器
再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。
Springboot自动转配原理之@Import注解处理过程
springboot
SpringBoot 自动配置探究
这里写目录标题pom.xml启动器主程序@ConditionalOnXXXX 注解yml 文件的配置是如何生效的?总结 pom.xml 当我们初始化一个 SpringBoot 工程,查看 pom.xml配置,发现有如下 依赖 <parent> <groupId>org.springframework.boot</groupId> <arti...
SpringBoot-自动配置-@Import注解与@EnableAutoConfiguration注解
SpringBoot-自动配置-@Import注解与@EnableAutoConfiguration注解
springboot整合mybatis源码分析
springboot整合mybatis源码分析 本文主要讲述mybatis在springboot中是如何被加载执行的,由于涉及的内容会比较多,所以这次只会对调用关系及关键代码点进行讲解,为了避免文章太长,读起来昏昏欲睡,一些不影响整体流程的细节就不涉及了。 1、预备知识 FactoryBean 什么是FactoryBean? 我们先看看FactoryBean的源码 //由 BeanFactory 中使用的对象实现的接口,这些对象本身是单个对象的工厂。如果一个 bean 实现了这个接口,它就被用作一个
【springboot】@Import的用法,与@ImportAutoConfiguration的区别
Import的value值,可以是配置类。
SpringBootApplication-@Import(AutoConfigurationImportSelector.class)
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage //标记自动配置 @Import(AutoConfigurationImportSelector.class) //使用Import自动导入所有符合自动配置条件的Bean定义并加载到IOC容器 public @interface EnableAutoConfiguration { ..
@Import和@ImportAutoConfiguration
`@Import(Config.class)` 和 `@ImportAutoConfiguration(Config.class)` 都是用来将指定的配置类加载到Spring的上下文中,虽然在功能上有一定的重叠——都可以用于导入配置类——但它们在使用场景和具体行为上有差异,因此在某些情况下,`@Import`不能直接替代`@ImportAutoConfiguration`。
SpringBoot中,@EnableAutoConfiguration包含的@AutoConfigurationPackage有什么用,具体做了什么
【代码】SpringBoot中,@EnableAutoConfiguration包含的@AutoConfigurationPackage有什么用,具体做了什么。
springboot源码3---自动装配
springboot自动装配原理、AutoConfigurationImportSelector
421



被折叠的 条评论
为什么被折叠?



