SpringBoot原理(包含详细追踪过程),包含自定义起步依赖的教程

SpringBoot原理

起步依赖

假如我们没有使用SpringBoot,用的是Spring框架进行web程序的开发,此时我们就需要引入web程序开发所需要的一些依赖。

当我们引入了 spring-boot-starter-web 之后,maven会通过**依赖传递**特性,将web开发所需的常见依赖都传递下来。

  • 在SpringBoot给我们提供的这些起步依赖当中,已提供了当前程序开发所需要的所有的常见依赖(官网地址:https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/#using.build-systems.starters)。

依赖传递

  • 比如:springboot-starter-web,这是web开发的起步依赖,在web开发的起步依赖当中,就集成了web开发中常见的依赖:json、web、webmvc、tomcat等。我们只需要引入这一个起步依赖,其他的依赖都会自动的通过Maven的依赖传递进来。

自动配置

SpringBoot的自动配置就是当spring(IOC)容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。

实现方案

首先在pom.xml中 引入需要自动配置的jar包坐标

@ComponentScan组件扫描

@SpringBootApplication
@ComponentScan({"com.example1","com.example2"}) //指定要扫描的包
public class SpringbootWebConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfigApplication.class, args);
    }
}
  • 使用繁琐
  • 性能低

@Import导入

导入普通类
@Import(Common.class) //导入的类会被Spring加载到IOC容器中
@SpringBootApplication
public class SpringbootWebConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfigApplication.class, args);
    }
}
导入配置类
  • 配置类: @Configuration 上面有个注解
@Configuration
public class HeaderConfig {
    @Bean
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
    @Bean
    public HeaderGenerator headerGenerator(){
        return new HeaderGenerator();
    }
}
  • 直接导入即可
@Import(HeaderConfig.class) //导入配置类
导入ImportSelector接口实现类
  • ImportSelector接口实现类:
public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //返回值字符串数组(数组中封装了全限定名称的类)
        return new String[]{"com.example.HeaderConfig"};
    }
}
  • 直接导入即可
@Import(MyImportSelector.class) //导入ImportSelector接口实现类
!!使用第三方依赖提供的 @EnableXxxxx注解! 常用

如果基于以上方式完成自动配置,当要引入一个第三方依赖时,还要提前知道第三方依赖中有哪些配置类和哪些Bean对象.

让第三方依赖给提供一个注解,这个注解一般都以@EnableXxxx开头的注解,注解中封装的就是@Import注解

  • 三方定义注解
  • 注解里@Import()指定了要导入哪些bean对象或配置类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)	// 指定要导入哪些bean对象或配置类
public @interface EnableHeaderConfig { 
}
  • 使用时直接在启动类上加上@EnableHeaderConfig
@EnableHeaderConfig  //使用第三方依赖提供的Enable开头的注解
@SpringBootApplication
public class SpringbootWebConfig2Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}

如此, 可以自动配置第三方提供好的配置类和Bean对象.

自动配置的原理

三大注解

自动配置核心:@EnableAutoConfiguration .

启动类上面有个@SpringBootApplication,是SpringBoot中最最重要的注解点开会发现:

image-20250506230830678

圈外为元注解,@SpringBootApplication由圈内三个部分组成:

  • @SpringBootConfiguration : 该注解与@Configuration 注解作用相同, 声明配置类
  • @EnableAutoConfiguration : 实现自动化配置的核心注解.
  • @ComponentScan : 组件扫描, 默认扫描当前引导类所在的包及其所有子包

启动类中默认的静态方法就是返回一个IOC容器对象

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

}

@EnableAutoConfiguration

  • 点进去发现@Import({AutoConfigurationImportSelector.class}), 作用是将AutoConfigurationImportSelector.class内所有的Bean都交给IOC容器管理

image-20250506231841256

  • AutoConfigurationImportSelector进去发现: 实现了DeferredImportSelector接口, 这个接口又实现了ImportSelector接口,

image-20250506232022673

ImportSelector接口

ImportSelector是Spring框架中的一个重要接口,主要作用是在@Configuration类中动态决定需要导入哪些配置类

  • 其抽象方法return的是 要导入的配置类的全限定名数组.

AutoConfigurationImportSelector

  • 重写了ImportSelector里的selectImports方法, 这里通过getAutoConfigurationEntry来获得配置类的全限定名数组

image-20250506233014282

  • 继续追踪, 可以看到getAutoConfigurationEntry返回的是configurations, 而configurations又是通过getCandidateConfigurations获得的.
  • 这个configurations具体包括了自动装配的是哪些Bean对象

image-20250506233141151

  • 继续追踪,这里的断言, 说名了自动装配类的文件存放位置, 主要找两个文件
    • spring.factories
    • org.springframework.boot.autoconfigure.AutoConfiguration.imports

image-20250506233601158

目的地

image-20250506234533858

  • 选中一个类, 点这个靶子可以找到这俩文件

image-20250506234617799

可以看到, 这俩文件里存放的都是Bean对象的全限定名

image-20250506234701235

image-20250506234712657

SpringBoot启动时,并不会将所有的Bean都交给IOC容器, 而是通过一些注解进行条件判断是否注入Bean.

自定义Start起步依赖

  • 在实际的开发中, 经常会定义一些公共组件, 提供给各个项目团队使用.

  • 在SpringBoot项目中, 一般会将这些公共组件封装为SpringBoot的starter, 传到maven的远程仓库(私服中).

  • 然后 引入 对应坐标的依赖, 即可快速使用这些功能

    • 配好依赖管理start, 自动配置会自动装配相关依赖

image-20250506235845387

下面就用阿里云OSS云存储功能来创建起步依赖.如上图

准备

  • 准备两个模块, 一个做starter, 一个做autoconfigure
  • starter不需要写代码, 所以Src文件夹可以删掉不要

image-20250507001632489

  • 将阿里云服务的工具类和配置类放入配置模块

image-20250507002339285

  • 配置模块的pom.xml配置好阿里云相关依赖, 并设置好坐标

    <groupId>aliyun-oss-spring-boot</groupId>
    <artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
    <version>1.0-SNAPSHOT</version>
    

建立联系

在starter模块的pom.xml中添加依赖, 和配置模块建立联系

<dependencies>
    <dependency>
        <groupId>aliyun-oss-spring-boot</groupId>
        <artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

使用

在需要使用此功能的模块引入依赖

<dependency>
    <groupId>aliyun-oss-spring-boot</groupId>
    <artifactId>aliyun-oss-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  • 此时发现, 可以注入, 但是对象用不了

image-20250507003703004

  • 原因是当前模块启动类扫描不到其他模块, 所以工具类的这俩注解也没用了, 可以删掉.配置类也同理

image-20250507004017050

image-20250507004117266

完成自动配置

配置模块并没有将工具类送给IOC容器, 还需进行配置.

自动装配类

创建一个类 AliyunOssAutoConfiguration

@Configuration
public class AliyunOssAutoConfiguration {
    // 将配置类作为参数传入, 目的是构建一个带参的工具类对象
    @Bean														   //这下面会报错,原因看下面
    public AliyunOSSOperator aliyunOSSOperator(AliyunOSSProperties aliyunOSSProperties) {
        AliyunOSSOperator aliyunOSSOperator = new AliyunOSSOperator();
        aliyunOSSOperator.setAliyunOSSProperties(aliyunOSSProperties);	// 在aliyunOSSOperator上面加上了@Data
        return aliyunOSSOperator;	//将这个带参的工具类对象交给IOC容器
    }
}
原因:

配置类没有注册为Bean, 它的对象不能直接使用.

解决办法:

加上@ConfigurationProperties(prefix = "aliyun.oss")注册为Bean

image-20250507011015435

装配类加上@EnableConfigurationProperties(AliyunOSSProperties.class)来使用Bean

image-20250507011145398

此时就不报错了,但是还没有完成自动配置.

  • 还没有/需要给SpringBoot准备起步时要扫描的文件META-INF/spring.factories.

真正的自动配置

在resource里创建文件 META-INF/spring.factories

org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
com.aliyun.oss.AliyunOssAutoConfiguration
  • \ 代表下一行 , 可以忽略
  • = 前面为Spring Boot定义的一个接口或抽象类,用于扩展数据库初始化依赖检测机制,理解为键即可
  • 后面为要交给IOC的全限定名

执行流程

  • 要使用此Bean的模块pom.xml文件中引入了starter, 程序启动首先找到这里

image-20250507012442318

  • 根据坐标定位到aliyun-oss-spring-boot-starter模块
  • 而aliyun-oss-spring-boot-starter的pom.xml中引入了aliyun-oss-spring-boot-autoconfigure

image-20250507012719203

  • 定位到aliyun-oss-spring-boot-autoconfigure, 程序会自动去找META-INF/spring.factories文件

image-20250507012835686

  • 通过此全限定名找到相应的类

image-20250507012925492

一看确实是配置类, 且有个@Bean注解, 此时才将这个类的对象return到IOC容器里

仍然报错

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原因
  • Spring Boot版本兼容性

  • spring.factories 是 Spring Boot 1.x 和 2.x 中使用的自动配置机制,如果使用的是 Spring Boot 3.x,则需要改用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件进行自动配置声明。

解决办法
  • 在META-INF下新建文件夹spring

  • 新建文件 org.springframework.boot.autoconfigure.AutoConfiguration.imports

  • 在文件内直接输入自动装配类的全限定名

    com.aliyun.oss.AliyunOssAutoConfigurationd
    

image-20250507014431693

  • 此时可以看到不报错了, 可以正常使用上传功能

image-20250507014558693

  • 运行项目测试了一下功能, 没有出现问题

    image-20250507014945323

如果仍然报错

Caused by: java.lang.IllegalArgumentException: Class [com.aliyun.oss.AliyunOssAutoConfiguration] is not assignable to factory type [org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector]

  • 此时可以看到不报错了, 可以正常使用上传功能

[外链图片转存中…(img-CivW09Ls-1754531343309)]

  • 运行项目测试了一下功能, 没有出现问题

    [外链图片转存中…(img-yu84c32D-1754531343310)]

如果仍然报错

Caused by: java.lang.IllegalArgumentException: Class [com.aliyun.oss.AliyunOssAutoConfiguration] is not assignable to factory type [org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector]

  • 那就删掉之前不兼容的spring.factories这个文件再次运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值