当前位置: 首页 > article >正文

@SpringBootApplication源码解析

1 简介

1.1 什么是自动装配?

自动装配是指 Spring Boot 在启动时,根据类路径上的依赖项自动配置应用程序。例如,如果你的应用程序依赖于 Spring Data JPA,Spring Boot 会自动配置一个 DataSourceEntityManagerFactory 和其他必要的 Bean,而无需你手动编写这些配置。

1.2 自动装配的工作原理
  1. 依赖管理:Spring Boot 使用 Maven 或 Gradle 管理依赖项。当你在 pom.xml 或 build.gradle 文件中添加依赖项时,Spring Boot 会检测这些依赖项。

  2. 自动配置类:Spring Boot 提供了一组自动配置类,这些类位于 spring-boot-autoconfigure 模块中。每个自动配置类都对应一个特定的技术栈或功能模块。

  3. 条件注解:自动配置类使用条件注解(如 @ConditionalOnClass@ConditionalOnMissingBean 等)来决定是否应用某个配置。这些注解确保只有在满足特定条件时才会应用配置。

2 源码解读

入口:@SpringBootApplication

//以下是@SpringBootApplication注解的内部信息 其中最核心的是后3条
@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) })

2.1 @SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
//这个注解的主要主要表明这是一个配置类 需要解析
public @interface SpringBootConfiguration {

    /**
     * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce
     * bean lifecycle behavior, e.g. to return shared singleton bean instances even in
     * case of direct {@code @Bean} method calls in user code. This feature requires
     * method interception, implemented through a runtime-generated CGLIB subclass which
     * comes with limitations such as the configuration class and its methods not being
     * allowed to declare {@code final}.
     * <p>
     * The default is {@code true}, allowing for 'inter-bean references' within the
     * configuration class as well as for external calls to this configuration's
     * {@code @Bean} methods, e.g. from another configuration class. If this is not needed
     * since each of this particular configuration's {@code @Bean} methods is
     * self-contained and designed as a plain factory method for container use, switch
     * this flag to {@code false} in order to avoid CGLIB subclass processing.
     * <p>
     * Turning off bean method interception effectively processes {@code @Bean} methods
     * individually like when declared on non-{@code @Configuration} classes, a.k.a.
     * "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally
     * equivalent to removing the {@code @Configuration} stereotype.
     * @return whether to proxy {@code @Bean} methods
     * @since 2.2
     */
    @AliasFor(annotation = Configuration.class)
    boolean proxyBeanMethods() default true;

}
2.2 @EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//自动注册一个basepackage的bean 作用是存储扫描路径 给其他组件使用
@AutoConfigurationPackage
//实现自动装配
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    /**
     * Environment property that can be used to override when auto-configuration is
     * enabled.
     */
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    Class<?>[] exclude() default {};

    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    String[] excludeName() default {};

}

2.2.1 @AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//引入注册器注册basepackage的bean
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

    /**
     * Base packages that should be registered with {@link AutoConfigurationPackages}.
     * <p>
     * Use {@link #basePackageClasses} for a type-safe alternative to String-based package
     * names.
     * @return the back package names
     * @since 2.3.0
     */
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages} for specifying the packages to be
     * registered with {@link AutoConfigurationPackages}.
     * <p>
     * Consider creating a special no-op marker class or interface in each package that
     * serves no purpose other than being referenced by this attribute.
     * @return the base package classes
     * @since 2.3.0
     */
    Class<?>[] basePackageClasses() default {};

}


static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
       //注册basepackage的bean
       register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
    }

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

}
2.2.2 @Import(AutoConfigurationImportSelector.class)
//这个我们先看实现的接口
//1 实现了DeferredImportSelector 而DeferredImportSelector继承了ImportSelector 作用是用来注册bean
//2 DeferredImportSelector对ImportSelector进行了增强 只有其他配置类扫描完了后 再解析这个引入的bean 为了确保条件注解的正确性
//3 重写了DeferredImportSelector的getImportGroup方法 调用好 优先会调用getImportGroup方法
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
       ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
       
       
public Class<? extends Group> getImportGroup() {
    //spring为注册分组的类 会自动调用该类的process方法
    return AutoConfigurationGroup.class;
}       


public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
          () -> String.format("Only %s implementations are supported, got %s",
                AutoConfigurationImportSelector.class.getSimpleName(),
                deferredImportSelector.getClass().getName()));
    //获取自动配置类            
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
       .getAutoConfigurationEntry(annotationMetadata);
    this.autoConfigurationEntries.add(autoConfigurationEntry);
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
       this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}


protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
       return EMPTY_ENTRY;
    }
    //1 获取注解的属性
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //2 扫描自动装配类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    //3 去重
    configurations = removeDuplicates(configurations);
    //4 获取过滤的bean集
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    //5 移除过滤的bean
    configurations.removeAll(exclusions);
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}


protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //加载配置文件获取配置
    List<String> configurations = new ArrayList<>(
          SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
    ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
    Assert.notEmpty(configurations,
          "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
                + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}


public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    ClassLoader classLoaderToUse = classLoader;
    if (classLoader == null) {
        classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    }

    String factoryTypeName = factoryType.getName();
    //加载配置文件获取配置
    return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}


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

        try {
        //从META-INF/spring.factories获取所有的自动装配类
            Enumeration<URL> 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()) {
                    Map.Entry<?, ?> entry = (Map.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);
        }
    }
}

2.3 @ComponentScan()

@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)

public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {

    private BeanFactory beanFactory;

    private Collection<TypeExcludeFilter> delegates;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
       this.beanFactory = beanFactory;
    }

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
          throws IOException {
          //去容器中获取所有类型为TypeExcludeFilter的bean 去执行过滤
          //我们可以实现这个方法 重写match方法 完成过滤
       if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {
          for (TypeExcludeFilter delegate : getDelegates()) {
             if (delegate.match(metadataReader, metadataReaderFactory)) {
                return true;
             }
          }
       }
       return false;
    }

    private Collection<TypeExcludeFilter> getDelegates() {
       Collection<TypeExcludeFilter> delegates = this.delegates;
       if (delegates == null) {
          delegates = ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();
          this.delegates = delegates;
       }
       return delegates;
    }

    @Override
    public boolean equals(Object obj) {
       throw new IllegalStateException("TypeExcludeFilter " + getClass() + " has not implemented equals");
    }

    @Override
    public int hashCode() {
       throw new IllegalStateException("TypeExcludeFilter " + getClass() + " has not implemented hashCode");
    }

}

@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) 


public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {

    private ClassLoader beanClassLoader;

    private volatile List<String> autoConfigurations;

    @Override
    public void setBeanClassLoader(ClassLoader beanClassLoader) {
       this.beanClassLoader = beanClassLoader;
    }

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
          throws IOException {
          //1 是否是一个配置类
          //2 是否有AutoConfiguration或者在自动装配类已配置
          //同时满足上面两个条件就不扫描这个bean
       return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
    }

    private boolean isConfiguration(MetadataReader metadataReader) {
       return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());
    }

    private boolean isAutoConfiguration(MetadataReader metadataReader) {
       boolean annotatedWithAutoConfiguration = metadataReader.getAnnotationMetadata()
          .isAnnotated(AutoConfiguration.class.getName());
       return annotatedWithAutoConfiguration
             || getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
    }

    protected List<String> getAutoConfigurations() {
       if (this.autoConfigurations == null) {
          List<String> autoConfigurations = new ArrayList<>(
                SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader));
          ImportCandidates.load(AutoConfiguration.class, this.beanClassLoader).forEach(autoConfigurations::add);
          this.autoConfigurations = autoConfigurations;
       }
       return this.autoConfigurations;
    }

}


http://www.kler.cn/a/390563.html

相关文章:

  • 不对称信息
  • AMD CPU下pytorch 多GPU运行卡死和死锁解决
  • 矢量拟合(1)Sanathanan–Koerner算法
  • python装饰器的使用以及私有化
  • Django博客网站上线前准备事项
  • 【2024最新】math-expression-evaluator 动态计算表达式的使用
  • 【ComfyUI +BrushNet+PowerPaint】图像修复(根据题词填充目标)——ComfyUI-BrushNet
  • shodan7(泷羽sec)
  • SystemVerilog学习笔记(一):数据类型
  • (C++)验证累加非原子操作以及vector和thread的结合使用(附fitten code插件安装方法,AI插件,帮忙填充代码)
  • Layui layui.treeTable 树表格组件 去除图标展示
  • rust模式和匹配
  • Redis经典面试题-深度剖析
  • Android dagger的使用
  • spring -第十四章 spring事务
  • D-Link NAS account_mgr.cgi 未授权RCE漏洞复现(CVE-2024-10914)
  • 48651
  • uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
  • C#基础-区分数组与集合
  • 微信小程序原生 canvas画布截取视频帧保存为图片并进行裁剪
  • 24/11/12 算法笔记<强化学习> Policy Gradient策略梯度
  • IT运维的365天--019 用php做一个简单的文件上传工具
  • go 下划线 _ 被称为“空白标识符
  • 【Lucene】全文检索 vs 顺序扫描,为何建立索引比逐个文件搜索更高效?
  • 第 4 章 - Go 语言变量与常量
  • 构造函数原型对象语法、原型链、原型对象