Spring Boot 自动配置原理 有图有动画还看不明白吗
为了方便测试,自定义了一个SprongBootStarter
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sgg.aopcache.cache.conf.RedissonAotoConfiguration
1.@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) })
看这个注解 @EnableAutoConfiguration 看名字就知道 开启自动配置
好,点进去这个注解
2. @EnableAutoConfiguration 开启自动配置注解
首先看下这个注解的元信息和属性
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { /** * Environment property that can be used to override when auto-configuration is * enabled. */ 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 {}; }
exclude() excludeName() 如果需要排除某些自动配置类 可以给这两个参数设置值
最重要的看这个注解
3.@Import(AutoConfigurationImportSelector.class)
@Import注解将某个组件导入spring容器中
我们看下 AutoConfigurationImportSelector 这个类都干了什么事情
找到这个方法 selectImports
调用了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); }
getBeanClassLoader()
可以看到这个方法的第二个参数获取了类加载器 想想我们自定义starter 的META-INF 文件夹是放在哪里的?
放在resource目录下,这个目录的路径由谁加载,由 AppClassLoader负责加载
点进loadFactoryNames 方法
4. SpringFactoriesLoader.loadFactoryNames
获取了 @EnableAutoConfiguration 注解的全限定类名
首先执行这个方法 loadSpringFactories(classLoader) 注意把类加载器传进去了
这个方法返回一个 Map<String, List<string>> </string>
然后再调用它的 .getOrDefault(factoryTypeName, Collections.emptyList()) 方法 也就是获取key = factoryTypeName 的value
而value 是一个String类型的集合 也就是自动配置类的全限定类名
我们跟进这个方法看一下
5.loadSpringFactories(classLoader)
重点看这个else代码块都做了什么事
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryTypeName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryImplementationName = var9[var11]; result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result;
如果是我们自定义的 spring.factories 配置文件,我们一般只会写 org.springframework.boot.autoconfigure.EnableAutoConfiguration= xxxx
而springboot官方的starter不单单只有
org.springframework.boot.autoconfigure.EnableAutoConfiguration
所以在这我们打断点多循环几次
最后可以看到 我们自定义starter 的 spring.factories文件信息已经被放到了 LinkedMultiValueMap result 中 并返回
返回前还将数据都放到了缓存中
至此,候选的自动配置类全限定类名都已经拿到了,之后还要经历筛选和过滤
最终返回经过了排除和过滤的自动配置类的全限定名数组
#Java开发##Spring##学习路径#