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

Springboot基础篇(4):自动配置原理

1 自动配置原理剖析

1.1 加载配置类的源码追溯

  1. 自动配置的触发入口: @SpringBootApplication 组合注解是自动配置的起点,其核心包含 @EnableAutoConfiguration,该注解使用AutoConfigurationImportSelector 实现配置类的动态加载。

ALt

启动类的注解@SpringBootApplication

//可以应用于类、接口(包括注解类型)和枚举声明
@Target(ElementType.TYPE)
//注解信息将在运行时保留
@Retention(RetentionPolicy.RUNTIME)
//在使用 Javadoc 工具生成 API 文档时,该注解将被包含在文档中
@Documented
//如果一个类使用了@SpringBootApplication 注解,那么它的子类也会继承这个注解
@Inherited
//springboot配置类
@SpringBootConfiguration
//核心:启用Spring Boot 的自动配置机制
@EnableAutoConfiguration
//启用组件扫描
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}
@SpringBootApplication注解
  1. 查看@EnableAutoConfiguration,@EnableAutoConfiguration注解上导入了AutoConfigurationImportSelector.class,该类负责选择和导入需要自动配置的类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//指定自动配置的包路径,通常用于扫描带有@Configuration 注解的类
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
3 @EnableAutoConfiguration注解
  1. 查看AutoConfigurationImportSelector.class,该类负责加载、筛选和返回需要加载的自动配置类
public class AutoConfigurationImportSelector implements ... {

    // 核心方法:选择并加载自动配置类
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    // 1. 检查是否启用自动配置
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS; // 如果未启用,返回空数组
    }
    // 2. 获取自动配置条目
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    // 3. 返回配置类数组
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
  1. 查看selectImports中调用的getAutoConfigurationEntry方法。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // 1. 检查是否启用自动配置
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY; // 如果未启用,返回空条目
    }
    // 2. 获取注解属性
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 3. 加载候选配置类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 4. 去重
    configurations = removeDuplicates(configurations);
    // 5. 获取排除项
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    // 6. 检查排除项
    checkExcludedClasses(configurations, exclusions);
    // 7. 过滤排除项
    configurations.removeAll(exclusions);
    // 8. 应用配置类过滤器
    configurations = getConfigurationClassFilter().filter(configurations);
    // 9. 触发事件
    fireAutoConfigurationImportEvents(configurations, exclusions);
    // 10. 返回结果
    return new AutoConfigurationEntry(configurations, exclusions);
}
  1. 查看getAutoConfigurationEntry方法调用的getCandidateConfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // 1. 加载候选配置类
    ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation, getBeanClassLoader());
    List<String> configurations = importCandidates.getCandidates();
    // 2. 检查配置类是否为空
    Assert.notEmpty(configurations,
            "No auto configuration classes found in " + "META-INF/spring/"
                    + this.autoConfigurationAnnotation.getName() + ".imports. If you "
                    + "are using a custom packaging, make sure that file is correct.");
    // 3. 返回配置类列表
    return configurations;
}
  1. 查看getCandidateConfigurations调用的load方法,可以看到该方法负责从类路径中加载指定注解对应的 .imports 文件,并解析文件内容。
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
    // 1. 检查注解是否为空
    Assert.notNull(annotation, "'annotation' must not be null");

    // 2. 决定类加载器
    ClassLoader classLoaderToUse = decideClassloader(classLoader);
    // 3. 构建文件路径
    String location = String.format("META-INF/spring/%s.imports", annotation.getName());
    // 4. 查找文件 URL
    Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
    // 5. 读取文件内容
    List<String> importCandidates = new ArrayList<>();
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        importCandidates.addAll(readCandidateConfigurations(url));
    }
    // 6. 返回结果
    return new ImportCandidates(importCandidates);
}
  1. 最后我们终于知道,@SpringBootApplication通过层层修饰,最后到了load方法,load方法扫描并读取类路径下的.imports文件中的配置类。

1.2 通过条件注解注册配置类

我们选择mybatis的包来介绍如何注册的

  1. 找到mybatis的自动配置包在这里插入图片描述

  2. 查看.imports文件
    在这里插入图片描述

  3. 查看部分配置类:这个类的含义是在满足以下条件时,自动配置并注册一个 FreeMarkerLanguageDriver Bean:
    a、 类路径中存在 FreeMarkerLanguageDriver 和 FreeMarkerLanguageDriverConfig 类。
    b、 Spring 容器中尚未注册 FreeMarkerLanguageDriver 类型的 Bean。

  @Configuration(proxyBeanMethods = false)
  @ConditionalOnClass({ FreeMarkerLanguageDriver.class, FreeMarkerLanguageDriverConfig.class })
  public static class FreeMarkerConfiguration {
    @Bean
    @ConditionalOnMissingBean
    FreeMarkerLanguageDriver freeMarkerLanguageDriver(FreeMarkerLanguageDriverConfig config) {
      return new FreeMarkerLanguageDriver(config);
    }
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration配置类的Bean

2 案例:自定义一个自动配置类

  1. 需求:写一个自动配置类,当访问http://localhost:8080/sayhello时,使用控制器使用自动配置类去打印“HELLO!”
  2. 创建业务类
public class GreetingService {
    private String message = "Hello!";
    public String sayHello() {
        return message;
    }
    // 支持自定义问候语
    public void setMessage(String message) {
        this.message = message;
    }
}
  1. 创建业务自动配置类
@Configuration
public class GreetingServiceAutoConfiguration {
    @Bean
    public GreetingService greetingService() {
        return new GreetingService();
    }
}

  1. 注册配置
    ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a6a07b374504405bb2f2afef1d91548a.png

  2. 编写控制器

@RestController
public class HelloController {
    @Autowired private GreetingService service;
    @RequestMapping("/hello")
    public String hello(){
        return "Hello World";
    }
    @RequestMapping("/sayhello")
    public String sayHello(){
        return service.sayHello();
    }
}

  1. 项目结构
    在这里插入图片描述
  2. 效果图
    在这里插入图片描述
http://www.dtcms.com/a/56068.html

相关文章:

  • Android Studio 配置国内镜像源
  • 【Python 数据结构 9.树】
  • elasticsearch学习
  • 告别手动复制粘贴:可定时自动备份的实用软件解析
  • 基金股票期权期货投资方式对比
  • 数字投屏叫号器-发射端python窗口定制
  • EB-Cable许可管理的重要性
  • 我用Ai学LVGL之入门(DeepSeek版)
  • 通义万相 2.1 携手蓝耘云平台:开启影视广告创意新纪元
  • 关于浏览器中的屏幕录制案例及源码
  • ApoorvCTF Rust语言逆向实战
  • SDIO(Secure Digital Input Output)详解
  • 纯html文件实现目录和文档关联
  • Java基于SringBoot的果树的生长信息管理系统,附源码+文档说明
  • Android studio如何导入外部项目至成功运行(适合纯新手、小白、初学者的详细教程)导入安卓项目时规避报错,鹿溪IT工作室为您服务
  • sqrt与sqrtl函数
  • Nginx:从入门到实战使用教程
  • 2025-03-07 学习记录--C/C++-PTA 习题8-5 使用函数实现字符串部分复制
  • Unity2017打包出来后的场景一片红
  • 解构OpenManus
  • 黑洞如何阻止光子逃逸
  • Spark Shuffle原理浅解析
  • ubuntu22.04本地部署OpenWebUI
  • 第6章 定时器计数器
  • Android APP 启动流程详解(含冷启动、热启动)
  • 在vue2项目中el-table表格的表头和内容错位问题
  • robot:生而为奴
  • 视觉语言模型新突破!苹果开源AIMv2,多模态融合性能提升10%!
  • nlp进阶
  • 200个前卫街头氛围涂鸦艺术水墨颜料手绘笔迹飞溅PNG免扣迭加纹理素材 VANTABLACK TEXTURES