spring boot自动配置类

前言

spring boot版本2.4.3
为什么说spring boot部署简单,且0代码生成,就是因为spring boot帮我们做了很多事情,其中自动配置类是一个很重要的因素。

1. 先看入口函数

@SpringBootApplication
public class WebApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }

}

ctrl+鼠标左键点进去@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}
)}
)

发现是一个合成注解,接下来一一解释。
元注解:
  @Target({ElementType.TYPE}),表示可标注在类,接口或枚举上。
  @Retention(RetentionPolicy.RUNTIME),表示注解会在class字节码文件中存在,在运行时可以通过反射获取到。
  @Documented,表示该注解将被包含在javadoc中。
  @Inherited,说明子类可以继承父类中的该注解。
注解:
  @SpringBootConfiguration,表示这是一个配置类
  @ComponentScan,包扫描规则,默认是主类所在的包及其子包
  @EnableAutoConfiguration,开启自动配置

2. @EnableAutoConfiguration

点开@EnableAutoConfiguration,发现他也是合成注解。

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}

2.1 @AutoConfigurationPackage

点进去发现

@Import({Registrar.class})
public @interface AutoConfigurationPackage {}

@Import({Registrar.class}),是导入一个配置类
点进去Registrar

  static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }
		//获取主类所在的包路径,并注册
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }

通过添加断点发现,在启动时只有第一个方法会执行,所实现的功能是将获取到的包名(默认是主类所在的包)注册,实质上是将包名添加到下面这个set中。

        private final Set<String> basePackages = new LinkedHashSet();

该set所在类为AutoConfigurationPackages下的BasePackagesBeanDefinition 静态内部类中

2.2 @Import({AutoConfigurationImportSelector.class})

点进去,里面有一个方法。叫获取候选的配置。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

里面这么多方法,是怎么找这个方法的?笨方法:将所有方法全部打上断点,然后debug运行,如果运行到其他类中,就step out,然后观察,前面都是一些初始化工作,到了上面的方法里面configurations突然就有值了。并且里面都是AutoConfiguration结尾的,那么此处就是找出所有需要自动配置的类。

在这里插入图片描述
122行是一个断言,做判断用的,不用管
明显主要逻辑是在121行执行的,打上断点,重新debug运行。

在121行按F7(进去参数方法,然后再出去),最终进入loadFactoryNames()方法
在这里插入图片描述
其中两个参数分别为org.springframework.boot.autoconfigure.EnableAutoConfiguration和RestartClassLoader

来到72行进入loadSpringFactories()方法
在这里插入图片描述
可以看到如果有缓存就从缓存获取,如果没有缓存就从META-INF/spring.factories中获取。会扫描spring所有的jar包下的META-INF/spring.factories文件,并获取其中的key和value放到map中。
在这里插入图片描述

以其中一个为例。
在这里插入图片描述
然后调用map的getOrDefault(factoryTypeName, Collections.emptyList())方法。意思是获取第一个参数key所对应的value,如果获取不到则返回第二个参数。
而上面的map里面是有org.springframework.boot.autoconfigure.EnableAutoConfiguration这个key的,所以会返回其对应的value。
在这里插入图片描述
注意只是获取候选的配置,并不一定会全部加载。

3. 加载

最终会按需加载,导入哪个包才会加载哪个。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值