SpringBoot面试题:(一)SpringBoot自动装配原理源码解析

源码研究
SpringBoot启动类:@SpringBootApplication注解

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

进入@SpringBootApplication注解

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

可以看到主要是三个注解构成
@SpringBootConfiguration:springboot配置类,spring组件
@EnableAutoConfiguration:开启自动配置
@ComponentScan:组件扫描

重点研究@EnableAutoConfiguration:

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})

@AutoConfigurationPackage:自动配置包
@Import({AutoConfigurationImportSelector.class}):导入自动配置选择器
进入选择器AutoConfigurationImportSelector.class

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

autoConfigurationEntry 就是自动配置类的信息,进入函数this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata)

    protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, 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.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationEntry(configurations, exclusions);
        }
    }

this.getCandidateConfigurations(annotationMetadata, attributes)获取配置类信息,并对配置类去重排序

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

通过SpringFactoriesLoader.loadFactoryNames获取配置类信息

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

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

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.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文件,k-v的形式读入缓存。
这样,springboot框架就可以读入到所有的配置类信息,在执行run方法时,解析上面的注解,将AutoConfigurationImportSelector加载进方法区,通过反射创建对象,调用其某一个方法,从缓存读取前面存储的k-v,并经过一系列的过滤、去重等,最后将需要的配置类加载,生成BD对象,创建Bean对象,放入spring容器。完成自动装配。

自动装配:自动装配就是把别人(官方)写好的config配置类加载到spring容器,然后根据这个配置类生成一些项目需要的bean对象。
但是自动配置类不一定生效,要根据条件判断是否成立,只要导入对应的start,自动装配才能生效。

@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {

我的理解:通过配置文件spring.factories批量获取配置类
SpringBoot自动装配的本质就是通过Spring去读取META-INF/spring.factories中保存的配置类文件然后加载bean定义的过程。
如果是标了@Configuration注解,就是批量加载了里面的bean定义;
如何实现 “自动”:通过配置文件获取对应的批量配置类,然后通过配置类批量加载bean定义,只要有写好的配置文件spring.factories就实现了自动
SpringBoot面试题:(一)SpringBoot自动装配原理源码解析_第1张图片

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