SpringBoot的自动配置原理

本文深入探讨了SpringBoot的自动配置原理,重点解析了@SpringBootApplication注解中的关键组件,包括@Configuration、@EnableAutoConfiguration和@ComponentScan。@EnableAutoConfiguration启动自动配置功能,依赖于@ImportResource加载配置和@ComponentScan扫描组件。自动配置主要通过读取META-INF/spring.factories文件中的配置信息,将对应的配置类加入到IOC容器中,实现"约定优于配置"的设计理念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot是目前软件中最主流的框架,无论是工作还是面试基本都有它的身影,SpringBoot主要解决了传统spring的重量级xml配置Bean,实现了自动装配;所以,我们也常在面试中被问到SpringBoot是如何实现自动装配。

1.1三个重要的注解

我们可以发现,在使用main()启动SpringBoot的时候,只有一个注解@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:我们点进去以后可以发现底层是Configuration注解,说白了就是支持JavaConfig的方式来进行配置(使用Configuration配置类等同于XML文件)。
  • @EnableAutoConfiguration:开启自动配置功能(后文详解)
  • @ComponentScan:这个注解,学过Spring的同学应该对它不会陌生,就是扫描注解,默认是扫描当前类下的package。将@Controller/@Service/@Component/@Repository等注解加载到IOC容器中。

所以,Springboothappleday01Application类可以被我们当做是这样的:

 点开@SpringBootApplication,可以发现它是一个组合注解,主要是由这么几个注解构成的。

@SpringBootConfiguration//核心
@EnableAutoConfiguration//核心
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

我们首先要研究的就是核心的两个注解 @SpringBootConfiguration@EnableAutoConfiguration,逐个进行分析。

@SpringBootConfiguration

@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Documented
@org.springframework.context.annotation.Configuration
@org.springframework.stereotype.Indexed
public @interface SpringBootConfiguration {
    @org.springframework.core.annotation.AliasFor(annotation = org.springframework.context.annotation.Configuration.class)
    boolean proxyBeanMethods() default true;

可以看到SpringBootConfiguration其实就携带了一个@Configuration注解,这个注解我们再熟悉不过了,他就代表自己是一个Spring的配置类。所以我们可以认为:@SpringBootConfiguration = @Configuration

@EnableAutoConfiguration

我们知道SpringBoot可以帮我们减少很多的配置,也肯定听过“约定大于配置”这么一句话,那SpringBoot是怎么做的呢?其实靠的就是@EnableAutoConfiguration注解。

简单来说,这个注解可以帮助我们自动载入应用程序所需要的所有默认配置

我们点进去看一下,发现有两个比较重要的注解:

@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Documented
@java.lang.annotation.Inherited
@org.springframework.boot.autoconfigure.AutoConfigurationPackage
@org.springframework.context.annotation.Import({org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    java.lang.String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    java.lang.Class<?>[] exclude() default {};

    java.lang.String[] excludeName() default {};
}
  • @AutoConfigurationPackage:自动配置包
  • @Import:给IOC容器导入组件

@AutoConfigurationPackage

网上将这个@AutoConfigurationPackage注解解释成自动配置包,我们也看看@AutoConfigurationPackage里边有什么:

@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Documented
@java.lang.annotation.Inherited
@org.springframework.context.annotation.Import({org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar.class})
public @interface AutoConfigurationPackage {
    java.lang.String[] basePackages() default {};

    java.lang.Class<?>[] basePackageClasses() default {};
}

我们可以发现,依靠的还是@Import注解,再点进去查看,我们发现重要的就是以下的代码:

	@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata,
				BeanDefinitionRegistry registry) {
			register(registry, new PackageImport(metadata).getPackageName());
		}

默认的情况下就是将:主配置类(@SpringBootApplication)的所在包及其子包里边的组件扫描到Spring容器中。

  • 看完这句话,会不会觉得,这不就是ComponentScan的功能吗?这俩不就重复了吗?

我开始也有这个疑问,直到我看到文档的这句话:

it will be used when scanning for code @Entity classes. It is generally recommended that you place EnableAutoConfiguration (if you’re not using @SpringBootApplication) in a root package so that all sub-packages and classes can be searched.

比如说,你用了Spring Data JPA,可能会在实体类上写@Entity注解。这个@Entity注解由@AutoConfigurationPackage扫描并加载,而我们平时开发用的@Controller/@Service/@Component/@Repository这些注解是由ComponentScan来扫描并加载的。

简单理解:这二者扫描的对象是不一样的。

回到Import

我们回到@Import(AutoConfigurationImportSelector.class)这句代码上,再点进去AutoConfigurationImportSelector.class看看具体的实现是什么:

我们再进去看一下这些配置信息是从哪里来的(进去getCandidateConfigurations方法):

 

 这里包装了一层,我们看到的只是通过SpringFactoriesLoader来加载,还没看到关键信息,继续进去

简单梳理:

  • FACTORIES_RESOURCE_LOCATION的值是META-INF/spring.factories
  • Spring启动的时候会扫描所有jar路径下的META-INF/spring.factories,将其文件包装成Properties对象
  • 从Properties对象获取到key值为EnableAutoConfiguration的数据,然后添加到容器里边。

 

 最后我们会默认加载113个默认的配置类:

总结

@SpringBootApplication等同于下面三个注解:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

其中@EnableAutoConfiguration是关键(启用自动配置),内部实际上就去加载META-INF/spring.factories文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值