1.默认提供的核心配置模块
springboot提供了 spring-boot-autoconfigure模块,该模块为springboot自动配置的核心模块,它初始化好了很多我们平时需要的配置类,那么有了这些配置类就能生效了吗?得需要一个东西在启动的时候去把它加载进容器里。
2.启动配置类注解 @SpringBootApplication
- @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 {
该注解是个复合注解,包含了
- @SpringBootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
这个注解触发了自动配置的过程。它实际上导入了 AutoConfigurationImportSelector 类,这个类负责决定哪些自动配置类应该被添加到应用上下文中。
这是一个复合注解,它包含了 @Configuration 注解,意味着当前类是一个配置类,可以包含一个或多个 @Bean 方法来定义组件。
- @EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
这个注解触发了自动配置的过程。它实际上导入了 AutoConfigurationImportSelector 类,这个类负责决定哪些自动配置类应该被添加到应用上下文中。
- AutoConfigurationImportSelector
AutoConfigurationImportSelector 类的 selectImports() 方法会返回一个字符串数组,即 factoryClassNames,这些类名代表了候选的自动配置类。这些类通常是 AutoConfigureXXX 的形式,它们会根据不同的条件(如类路径上的类、系统属性、环境变量等)来决定是否应该被激活。
3.条件注解,选择性加载
再来看这些配置类的具体实现,随便找一个
这些类上了使用条件注解,@Conditional**,这些条件控制了这些配置类什么时候生效,也就是说,当我们需要使用新的功能时必须引入这些依赖,导入对应的start pom, 导入之后这些配置类才会生效。
4.配置类的维护
在该依赖模块下的 META-INF/spring.factories 文件里提供了所有需要自动装配的配置类,
所有满足条件的自动配置类会通过 @Bean 方法创建并注册新的 Bean 到 Spring 容器中。
5.组件扫描
Spring Boot 会扫描标注了 @SpringBootApplication 的主类以及其子包,寻找带有 @Component、@Service、@Repository 和 @Controller 等注解的类,并将它们作为 Bean 注册到容器中。
6.依赖注入
所有注册的 Bean 将根据其定义的依赖关系进行自动装配,例如使用 @Autowired 注解。
7.源码细节
1.初始化自动配置类
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
MultiValueMap<String, String> 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()) {
Map.Entry<?, ?> entry = (Map.Entry)var6.next();
List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
IOException ex = var9;
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", ex);
}
}
}
2.容器启动-> 进入AutoConfigurationImportSelector->
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
//加载所有的自动配置类
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获取候选配置 获取满足条件的自动配置类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
//获取在springboot启动类上的排除的类 如@SpringBootApplication(scanBasePackages = //{"com.crpcg.ohps.weixin"}, exclude = {RabbitAutoConfiguration.class})
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
//移除需要排除的配置类
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
//继续往下看 下面有详细的源码
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
->进入到fireAutoConfigurationImportEvents方法
参数
configurations 自动配置类
exclusions 需要排除的配置类
源码基础补充
AutoConfigurationImportListener 会遍历这个列表,对于每一个自动配置类,它会检查该类是否满足激活条件(如 @ConditionalOnClass、@ConditionalOnBean、@ConditionalOnProperty 等)。如果条件满足,它会将该类注册为一个 Bean 定义,这样 Spring 容器就能在后续的初始化过程中创建和管理这些 Bean。
private 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) {
//继续往里面看再下面
invokeAwareMethods(listener);
//处理自动配置的导入和激活。
listener.onAutoConfigurationImportEvent(event);
}
}
}
listeners变量实例化之后的值,是一个条件判断listener
再往里看,执行的
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);
}
}
}
目前处于对象创建阶段,所以进入到了BeanFactoryAware
执行完返回继续执行
listener.onAutoConfigurationImportEvent(event);
//在注册自动配置类的过程中,onAutoConfigurationImportEvent 方法会评估每个自动配置类上的条件注解,如 //@ConditionalOnClass、@ConditionalOnBean、@ConditionalOnMissingBean 等,以确定它们是否应该被实际激活。
public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
if (this.beanFactory != null) {
//这个报告记录了哪些条件被评估以及它们的结果。这对于调试和理解为什么某些自动配置类被激活或未被激活是非常有用的。
ConditionEvaluationReport report = ConditionEvaluationReport
.get(this.beanFactory);
report.recordEvaluationCandidates(event.getCandidateConfigurations());
report.recordExclusions(event.getExclusions());
}
}
Spring Boot 会启动一个监听器,监听应用上下文的启动事件,一旦所有的 Bean 加载完毕,监听器会触发 ApplicationReadyEvent 事件,表明应用已经准备好接受请求。这样就完成了整个配置类的加载