SpringBoot自动装配原理

@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, ElementType.METHOD})--》可以修饰在类与方法上
@Retention(RetentionPolicy.RUNTIME)--》注解生效节点runtime
@Documented--》生成文档

然后是@SpringBootConfiguration:其实就是@Configuration,标注在哪就说明这是一个SpringBoot配置类,用来配置bean,所以有了这个注解之后我们可以在SpringBoot运行的主类中使用@Bean标签配置类了。

但是并不是所有的bean都会被初始化 ,在配置类中使用Condition来加载满足条件的bean;

在springBoot-autoconfigure的condition包下
1.ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean.

2.ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean

3.ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

4.ConditionalOnBean:判断环境中有对应Bean才初始化Bean

@ComponentScan:组件扫描,扫描SpringBoot主启动类的同级路径及子路径,将这个bean定义加载到IOC容器中。

@EnableAutoConfiguration:开启自动配置功能,有了这个注解,就会告诉SpringBoot开启自动配置功能

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

@AutoConfigurationPackage:自动配置包,将主配置类(@SpringBootApplication标注的类)的所在包及下面所有的子包里面的所有组件扫描到Spring容器中。
@Import注解:导入的类会被加载到IOC容器中,实现bean的动态加载,有四种用法

1.导入bean

2.导入配置类

3.导入ImportSelector实现类。一般用于加载配置文件中的类

4.导入ImportBeanDefinitionRegistrar实现类

其中@Import({AutoConfigurationImportSelector.class})这个注解是给容器导入组件

AutoConfigurationImportSelector:自动配置导入选择器,给容器导入一些组件

然后进入

  protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set 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);
        }
    }

通过getCandidateConfigurations()得到候选配置类

    protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List 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;
    }

然后加载这些META-INF/spring.factories文件,通过文件名获取每个配置类的url,再通过这些url将他们封装成Properties对象,最后解析内容存在map>中。

private static Map> loadSpringFactories(ClassLoader classLoader) {
        Map> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                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 factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

最终,getCandidateConfigurations()方法获取到了候选配置类并存于List中。之所以说是“候选”,是因为它们后续还需要经过一系列的去重、排除、过滤等操作,通过selectImports()方法返回一个自动配置类的全限定名数组,然后将所有自动配置类加载到Spring容器中,当SpringBoot容器启动时会自动加载配置类,初始化bean。这样就实现了自动装配。

你可能感兴趣的:(spring,boot,spring,java)