【详细的springboot自动装载原理】

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 事件,表明应用已经准备好接受请求。这样就完成了整个配置类的加载

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值