什么是SpringBoot装配SpringBoot是如何实现自动装配的
核心注解SpringBootApplication@EnableAutoConfiguration:实现自动装配的核心注解
(1) @AutoConfigurationPackage:(2) @import(AutoConfigurationimportSelector.class)(3)getAutoConfigurationEntry()方法调用链 SpringBoot中的按需加载注解原文链接
什么是SpringBoot装配我们现在提到自动装配的时候,一般会和 Spring Boot 联系在一起。但是,实际上 Spring framework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进一步优化。
SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的meta-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。
没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。
org.springframework.boot spring-boot-starter-data-redis
引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。
在我看来,自动装配可以简单理解为:通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。
SpringBoot是如何实现自动装配的 核心注解SpringBootApplicationSpringBoot核心注解:
@@SpringBootApplication
核心注解相当于以下三个注解:
@Configuration @EnableAutoConfiguration @ComponentScan()
这三个注解分别有如下作用:
@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类@EnableAutoConfiguration:启用 SpringBoot 的自动配置机制@ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilter和AutoConfigurationExcludeFilter。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@EnableAutoConfiguration:实现自动装配的核心注解
EnableAutoConfiguration 只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationimportSelector类。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所欲组件注册到容器中
@import({AutoConfigurationimportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
(1) @AutoConfigurationPackage:
@import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
//利用Register给容器中导入一系列组件
//将指定一个包下的所有组件导入进来,,
Register源码:
static class Registrar implements importBeanDefinitionRegistrar, Determinableimports {
@Override
public void registerBeanDefinitions(Annotationmetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new Packageimports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set
(2) @import(AutoConfigurationimportSelector.class)
public @interface import
AutoConfigurationimportSelector 部分源码
@Override
public String[] selectimports(Annotationmetadata annotationmetadata) {
if (!isEnabled(annotationmetadata)) {
return NO_importS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationmetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(Annotationmetadata annotationmetadata) {
if (!isEnabled(annotationmetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationmetadata);
List configurations = getCandidateConfigurations(annotationmetadata, attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationmetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationimportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
- 利用getAutoConfigurationEntry(annotationmetadata);;给容器中批量导入一些组件。调用List configurations = getCandidateConfigurations(annotationmetadata, attributes);获取到所有需要导入到容器中的组件利用工厂加载
Listconfigurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Map > loadSpringFactories(ClassLoader classLoader) 得到所有组件
- 从"meta-INF/spring.factories" 加载一个文件。默认扫描我们当前系统里面所有meta-INF/spring.factories位置的文件。。
spring-boot-autoconfigure-2.4.11.jar 包里面也有。
其下spring.factories里面 (springboot版本为2.4.11 共有130AutoConfiguration配置类)
@ConditionalOnBean:当容器里有指定 Bean 的条件下
@ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
@ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
@ConditionalOnClass:当类路径下有指定类的条件下
@ConditionalOnMissingClass:当类路径下没有指定类的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnexpression:基于 SpEL 表达式作为判断条件
@ConditionalOnJava:基于 Java 版本作为判断条件
@ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
@ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
@ConditionalOnWebApplication:当前项目是 Web 项 目的条件下
https://javaguide.cn/system-design/framework/spring/spring-boot-auto-assembly-principles.html



