SpringBoot自动配置原理
SpringBoot项目无需各种配置文件,一个main方法,就能把项目启动起来。那么我们看看SpringBoot是如何进行自动配置和启动的。
先看下图的SpringBoot项目的启动类
SpringBoot程序能够实现自动配置主要来源于@SpringBootApplication这个复合注解,其中有三个注解是比较重要的:
1.@ComponentScan注解(扫描注解)
这个注解在Spring中很重要,它对应XML配置中的元素
作用:自动扫描包(扫描当前主启动类同级的包)并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中。
2.@SpringBootConfiguration注解
表明这是一个SpringBoot配置类,配置类就是对应Spring的xml配置文件
3.@EnableAutoConfiguration注解
开启自动配置功能,里面包含两个比较重要的注解@AutoConfigurationPackage和@Import。
@AutoConfigurationPackage:自动配置包
@Import : ( 自动注册包和@ComponentScan自动扫描包,是联动的)Spring底层注解@Import,给容器中导入一个组件。
Registrar.class 作用:将主启动类所在包及包下面所有子包里面的所有组件扫描到Spring容器
@Import(AutoConfigurationImportSelector.class): 给容器导入组件
此注解是自动装配的核心注解,其导入的AutoConfigurationImportSelector类中有个selectImports( )方法, 此方法中有一个 getAutoConfigurationEntry( )方法用于获取自动配置的实体,
getAutoConfigurationEntry( )方法中有一个 this.getCandidateConfigurations(annotationMetadata, attributes) 获得候选配置的方法
getCandidateConfigurations()这个方法又调用SpringFactoriesLoader 类的静态方法!
我们进入SpringFactoriesLoader类loadFactoryNames() 方法------->获取所有的加载配置。
然后继续点击查看 loadSpringFactories 方法
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null) { return result; } else { HashMap result = new HashMap(); try { Enumeration urls = classLoader.getResources("META-INF/spring.factories"); 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[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); String[] var10 = factoryImplementationNames; int var11 = factoryImplementationNames.length; for(int var12 = 0; var12 < var11; ++var12) { String factoryImplementationName = var10[var12]; ((List)result.computeIfAbsent(factoryTypeName, (key) -> { return new ArrayList(); })).add(factoryImplementationName.trim()); } } } result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); }); cache.put(classLoader, result); return result; } catch (IOException var14) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); } } }
loadSpringFactories 方法中的classLoader.getResources(“META-INF/spring.factories”) —》获取项目资源;
spring-boot-autoconfigure jar 包下就有这样一个spring.factories文件。打开,如下图可以看到所有需要配置的类全路径都在文件中,每行一个配置,多个类名逗号分隔,而\表示忽略换行
可以看出 spring.factories 文件可以将项目包以外的 bean(即在 pom 文件中添加依赖中的 bean)注册到 spring 容器。由于@ComponentScan 注解只能扫描项目包内的 bean并注册到spring容器中,因此需要 @EnableAutoConfiguration 注解来注册项目包外的bean。而 spring.factories 文件,则是用来记录项目包外需要注册的bean类名。
思考:这么多自动配置为什么有的没有生效,需要导入对应的start才能有作用!