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就实现了自动
在这里插入图片描述

相关推荐

  1. SpringBoot-SpringBoot自动配置底层

    2023-12-07 22:14:05       44 阅读
  2. SpringBoot --附包扫描、自动装配原理面试

    2023-12-07 22:14:05       23 阅读
  3. SpringBoot

    2023-12-07 22:14:05       60 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-07 22:14:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-07 22:14:05       101 阅读
  3. 在Django里面运行非项目文件

    2023-12-07 22:14:05       82 阅读
  4. Python语言-面向对象

    2023-12-07 22:14:05       91 阅读

热门阅读

  1. 【小程序】小程序开发教程入门到精通

    2023-12-07 22:14:05       48 阅读
  2. vsto 用‘解决科学计数法显示的问题

    2023-12-07 22:14:05       59 阅读
  3. HTTP请求方法

    2023-12-07 22:14:05       52 阅读
  4. Amazon CodeWhisperer 正式发布可免费供个人使用

    2023-12-07 22:14:05       61 阅读
  5. 软件工程期末复习(2)

    2023-12-07 22:14:05       57 阅读
  6. (三)python单例模式

    2023-12-07 22:14:05       48 阅读
  7. 面向LLM的App架构——业务维度

    2023-12-07 22:14:05       48 阅读