-
Author: HuiFer
-
源码阅读仓库: SourceHot-spring-boot
-
org.springframework.boot.autoconfigure.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 { @AliasFor(annotation = EnableAutoConfiguration.class) Class<?>[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
EnableAutoConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }
AutoConfigurationImportSelector
-
类图
getAutoConfigurationMetadata()
@Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry( // 加载配置元数据 getAutoConfigurationMetadata(), annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } } private AutoConfigurationMetadata getAutoConfigurationMetadata() { if (this.autoConfigurationMetadata == null) { // 加载配置信息 this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); } return this.autoConfigurationMetadata; }
-
org.springframework.boot.autoconfigure.AutoConfigurationMetadataLoader#loadMetadata(java.lang.ClassLoader)
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) { try { // 获取资源路径 Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path) : ClassLoader.getSystemResources(path); Properties properties = new Properties(); while (urls.hasMoreElements()) { properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement()))); } return loadMetadata(properties); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex); } }
-
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
注意: 这个文件在target编译后的文件夹中
相关 Issues : https://github.com/spring-projects/spring-boot/issues/11282
-
自动装配
spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
该文件内存有:
# Auto Configure 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,\
同样找一下 redis
-
仔细看
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
类
先说注解
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
EnableConfigurationProperties
自动映射一个POJO到Spring Boot配置文件(默认是application.properties文件)的属性集。
-
org.springframework.boot.autoconfigure.data.redis.RedisProperties
-
部分 redis 配置属性
@ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { /** * Database index used by the connection factory. */ private int database = 0; /** * Connection URL. Overrides host, port, and password. User is ignored. Example: * redis://user:password@example.com:6379 */ private String url; /** * Redis server host. */ private String host = "localhost"; /** * Login password of the redis server. */ private String password; /** * Redis server port. */ private int port = 6379; /** * Whether to enable SSL support. */ private boolean ssl; /** * Connection timeout. */ private Duration timeout; /** * Client name to be set on connections with CLIENT SETNAME. */ private String clientName; }
-
找到一个我们用相同方式去寻找到别的一些属性处理如
org.springframework.boot.autoconfigure.jdbc.JdbcProperties
具体展开请各位读者自行了解了
AnnotationMetadata
回过头继续我们的主要流程
-
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process
再此之前我们看过了getAutoConfigurationMetadata()
的相关操作
关注 AnnotationMetadata annotationMetadata
存储了一些什么
这里简单理解
-
mergedAnnotations 类相关的注解信息
-
annotationTypes 在启动类上的注解列表
getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // 获取注解属性值 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 获取候选配置信息 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 删除重复配置 configurations = removeDuplicates(configurations); // 获取 exclude 属性 Set<String> exclusions = getExclusions(annotationMetadata, attributes); // 校验 exclude 类 checkExcludedClasses(configurations, exclusions); // 配置中删除 exclude 的6属性值 configurations.removeAll(exclusions); // 过滤 configurations = filter(configurations, autoConfigurationMetadata); // 触发自动配置事件 fireAutoConfigurationImportEvents(configurations, exclusions); // 返回 return new AutoConfigurationEntry(configurations, exclusions); }
getAttributes
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) { // name = org.springframework.boot.autoconfigure.EnableAutoConfiguration , 这是一个固定的值 String name = getAnnotationClass().getName(); // 获取注解的属性 AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true)); Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?"); return attributes; }
getCandidateConfigurations
-
读取
spring.factories
数据
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { // 读取 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; }
-
第一个是我自己写的一个测试用
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.sourcehot.service.HelloServiceAutoConfiguration
removeDuplicates
-
new 两个对象直接做数据转换,去重
protected final <T> List<T> removeDuplicates(List<T> list) { return new ArrayList<>(new LinkedHashSet<>(list)); }
getExclusions
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) { Set<String> excluded = new LinkedHashSet<>(); // 获取属性 exclude 值转换成list excluded.addAll(asList(attributes, "exclude")); // 获取属性 excludeName 值转换成list excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName"))); // 获取 SpringBoot 本身的忽略配置属性 excluded.addAll(getExcludeAutoConfigurationsProperty()); return excluded; }
getExcludeAutoConfigurationsProperty
private List<String> getExcludeAutoConfigurationsProperty() { if (getEnvironment() instanceof ConfigurableEnvironment) { Binder binder = Binder.get(getEnvironment()); // 取出 "spring.autoconfigure.exclude" 转换成list return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList) .orElse(Collections.emptyList()); } String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class); return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList(); }
-
修改启动类
@SpringBootApplication(excludeName = { "org.sourcehot.service.HelloServiceAutoConfiguration" })
checkExcludedClasses
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()) { // 处理忽略的类 handleInvalidExcludes(invalidExcludes); } }
-
configurations.removeAll(exclusions)
移除忽略的类
filter
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; // 获取 AutoConfigurationImportFilter 相关配置 for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { // 执行 aware 相关接口 invokeAwareMethods(filter); // 比较 boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; 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]); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms"); } return new ArrayList<>(result); }
-
getAutoConfigurationImportFilters()
从spring.factories
获取AutoConfigurationImportFilter
的接口
-
循环内执行
Aware
系列接口
match
方法: org.springframework.boot.autoconfigure.AutoConfigurationImportFilter#match
-
filter.match(candidates, autoConfigurationMetadata)
比较判断哪些是需要自动注入的类
fireAutoConfigurationImportEvents
rivate void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) { // 获取自动配置的监听器列表 List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners(); if (!listeners.isEmpty()) { // 创建 自动配置事件 AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions); for (AutoConfigurationImportListener listener : listeners) { // 执行 Aware 相关接口 invokeAwareMethods(listener); // 监听器执行自动配置事件 listener.onAutoConfigurationImportEvent(event); } } }
-
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
-
org.springframework.boot.autoconfigure.AutoConfigurationImportListener#onAutoConfigurationImportEvent
在执行自动配置时触发 , 实现类只有ConditionEvaluationReportAutoConfigurationImportListener
@Override public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) { if (this.beanFactory != null) { ConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory); // 记录需要加载的配置 report.recordEvaluationCandidates(event.getCandidateConfigurations()); // 记录不需要加载的配置 report.recordExclusions(event.getExclusions()); } }
-
初始化完
process
-
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process
-
后续的一些行为相对简单,直接放个源码了.
@Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); // 自动装配信息 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry( // 加载配置元数据 getAutoConfigurationMetadata(), annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); // 循环需要自动注入的类 for (String importClassName : autoConfigurationEntry.getConfigurations()) { // 继续放入k,v this.entries.putIfAbsent(importClassName, annotationMetadata); } }
selectImports
@Override 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 sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList()); }
后续由 spring 进行不再继续跟踪