SpringBoot的自动装配

SpringBoot通过@EnableAutoConfiguration注解开启自动配置,扫描spring.factories文件加载自动配置类。@SpringBootApplication是主要配置类,包含@SpringBootConfiguration、@ComponentScan和@EnableAutoConfiguration。自动配置类生效基于@Conditional注解的条件。通过设置debug=true,可在启动时查看自动配置报告。
摘要由CSDN通过智能技术生成

Spring Boot通过@EnableAutoConfiguration注解开启自动配置,对jar包下的spring.factories文件进行扫描,这个文件中包含了可以进行自动配置的类,当满足@Condition注解指定的条件时,便在依赖的支持下进行实例化,注册到Spring容器中。

@SpringBootApplication

在这里插入图片描述

作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;

@SpringBootApplication是一个复合注解或派生注解,进入该注解:

在这里插入图片描述

该类主要包括三个注解:

1、@SpringBootConfiguration

作用:SpringBoot的配置类,标注在某个类上,表示这是一个SpringBoot的配置类。

进入查看源码:
在这里插入图片描述

@Configuration标注在某个类上,表示这是一个 springboot的配置类,可以向容器中注入组件

2、@ComponentScan

作用:自动扫描组件,默认扫描该类所在包及其子包下所有带有指定注解的类,将它们自动装配到bean容器中,会被自动装配的注解包括@Controller、@Service、@Component、@Repository等。也可以指定扫描路径。

3、@EnableAutoConfiguration

开启自动配置功能,工程中需要配置的东西,SpringBoot会帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能。这样自动配置才会生效。

进入注解查看:

在这里插入图片描述

可以发现这个注解也是个复合注解。其中有两个较为重要的注解:

(1)@AutoConfigurationPackage

自动导入配置包
在这里插入图片描述

@import :Spring底层注解@import , 给容器中导入一个组件

进入Registrar.class查看源代码:

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));
    }
}

打断点测试可以得到:

(String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])的值为com.ljw.springbootwork:当前启动类所在的包名。

总结:@AutoConfigurationPackage就是将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器中 ;

(2)@Import({AutoConfigurationImportSelector.class})

给容器导入组件

AutoConfigurationImportSelector.class:开启自动配置类的导包的选择器,即是导入哪些类

进入AutoConfigurationImportSelector.class查看源码:

1、selectImports:选择需要导入的组件
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}
2、getAutoConfigurationEntry:

根据导入的@Configuration类的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    } else {
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
         // 这打个断点,看看 返回的数据
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        // 删除重复项
        configurations = this.removeDuplicates(configurations);
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        // 检查
        this.checkExcludedClasses(configurations, exclusions);
        // 删除需要排除的依赖
        configurations.removeAll(exclusions);
        configurations = this.getConfigurationClassFilter().filter(configurations);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}
3、getCandidateConfigurations(AnnotationMetadata,AnnotationAttributes )
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;
    }

Assert(断言):在META-INF/spring.factories中没有找到自动配置类。如果您正在使用自定义打包,请确保该文件是正确的。

所以loadFactoryNames()方法要找到自动配置类返回才不会报错。

3.1 进入getSpringFactoriesLoaderFactoryClass()方法
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
     return EnableAutoConfiguration.class;
}

结论:获取一个加载自动配置类的类,即SpringBoot默认自动配置类为EnableAutoConfiguration

3.2 loadFactoryNames()

getCandidateConfigurations()方法又调用了SpringFactoriesLoader类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法。

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    //这里它又调用了 loadSpringFactories 方法
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
3.3 loadSpringFactories()
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
    MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        try {
            //去获取一个资源 "META-INF/spring.factories"
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            LinkedMultiValueMap result = new LinkedMultiValueMap();

            //将读取到的资源遍历,封装成为一个Properties
            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()) {
                    Entry<?, ?> entry = (Entry)var6.next();
                    String factoryClassName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryName = var9[var11];
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

该方法作用是加载所有依赖的路径META-INF/spring.factories文件,通过map结构保存,key为文件中定义的一些标识工厂类,value就是能自动配置的一些工厂实现的类,value用list保存并去重

3.4 spring.factories

打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在.

小结:

这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

SpringBoot自动配置原理流程图

在这里插入图片描述

自动配置生效

自动配置类必须在一定的条件下才能生效使用,虽然在SpringBoot中加载了很多的自动配置,但是并不是每个自动配置类都会生效,但是在使用的时候需要在一定条件下才会生效,这个就需要通过使用这些判断条件来实现。

依赖于Configuration类中的@Conditional注解,注解指定的条件成立时,才会给容器中添加组件,yml文件中的配置才会生效。

我们如何知道哪些配置类生效了?

在yml文件中写上debug=true属性,来让控制台打印自动配置报告,控制台会显示对应信息。

总结:

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  2. 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
  3. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  4. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
  5. 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网底层民工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值