一,SpringBoot介绍
Spring Boot 是 Spring 生态中的一款 快速开发框架,旨在简化基于 Spring 的应用搭建和配置流程。它通过 约定优于配置 的设计理念,提供开箱即用的功能,让开发者专注于业务逻辑而非复杂的配置。Spring Boot 常被用于构建独立运行、生产级的微服务或单体应用。
核心特性
- 自动配置(Auto-Configuration)
- 根据项目依赖(如 JDBC、Web、Security)自动配置 Spring 应用,无需手动编写 XML 或 Java 配置。
- 例如:引入
spring-boot-starter-web后,自动配置 Spring MVC 和嵌入式 Tomcat。
- 内嵌服务器(Embedded Server)
- 默认集成 Tomcat、Jetty 或 Undertow,应用可直接打包为 可执行 JAR,无需部署到外部 Web 服务器。
- 通过一行命令即可启动:
java -jar app.jar。
- Starter 依赖(Starters)
- 提供预定义的依赖集合(如
spring-boot-starter-data-jpa、spring-boot-starter-security),简化依赖管理。 - 避免手动解决库版本冲突问题。
- 提供预定义的依赖集合(如
- 生产就绪(Production-Ready)
- 集成 Actuator 模块,提供监控端点(如健康检查、指标收集、日志管理)。
- 支持通过 HTTP 或 JMX 监控应用状态。
- 外部化配置
- 支持通过
application.properties或application.yml文件灵活配置应用参数。 - 支持多环境配置(如
application-dev.yml、application-prod.yml)。
- 支持通过
- 无代码生成与零 XML 配置
- 完全基于 Java 注解和约定,无需生成代码或编写 XML。
二,快速入门
Spring程序与SpringBoot程序对比
三,SpringBoot项目快速启动
-
对SpringBoot项目打包(执行Maven构建指令package)
-
执行启动命令
java -jar springboot.jar
切换Tomcat服务器为Jetty服务器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
四,起步依赖
Spring Boot 的 起步依赖(Starter Dependencies) 是其简化项目依赖管理的核心机制之一。它通过预定义的依赖集合和版本管理,让开发者能够快速引入特定功能所需的所有库,避免手动处理依赖冲突和版本兼容性问题。
起步依赖的核心思想
- 约定优于配置
- 每个 Starter 对应一个特定功能(如 Web 开发、数据库访问、安全等),一键引入相关依赖。
- 开发者无需手动查找和配置依赖的版本,Spring Boot 自动确保版本兼容性。
- 依赖传递性
- Starter 内部通过 Maven/Gradle 的依赖传递机制,自动引入功能所需的所有关联库。
- 例如:
spring-boot-starter-web会传递引入 Spring MVC、Tomcat、Jackson 等依赖。
工作原理
-
依赖聚合与版本管理
-
父 POM 管理:通过继承
spring-boot-starter-parent,项目自动继承 Spring Boot 统一管理的依赖版本。<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.0</version> </parent> -
BOM(Bill of Materials):若无法继承父 POM,可使用
<dependencyManagement>引入spring-boot-dependencies,统一版本管理。
-
-
Starter 的内部结构
-
每个 Starter 仅是一个 空 JAR,其
pom.xml中声明了相关依赖。 -
例如:
spring-boot-starter-web的依赖树:spring-boot-starter-web ├── spring-boot-starter ├── spring-boot-starter-json ├── spring-boot-starter-tomcat ├── spring-webmvc └── spring-web
-
五,自动装配
5.1 将自定义类交给IOC容器
假设我们在第三方工具jar包中定义了工具类需要较给Spring的IOC容器管理,因为Spring包扫描默认是启动类所在包下的,所有直接用@Compnent等相关注解是无法将自定义类交给IOC容器管理的。
-
方案1:
@ComponentScan({"com.example","com.example2"})组件扫描在启动类上添加包扫描即可解决
@ComponentScan({"com.example","com.example2"}) @SpringBootApplication public class SpringBootWeb{ }这个方案如果我们有大量类需要较给IOC容器管理要写很多,会很繁琐,不方便阅读
-
方案2:
@Import导入。使用 @Import导入的类会被Spring加载到IOC容器中,导入形式主要有:
-
导入普通类
@Import({TokenParser.class}) @SpringBootApplication public class SpringBootWeb{ }通过Import导入的普通类不需要加入@Component这种注解可以直接将其交给IOC容器管理
-
导入配置类
@Import({HeaderConfig.class}) @SpringBootApplication public class SpringBootWeb{ }HeaderConfig的内容为
@Configuration public class HeaderConfig{ @Bean public HeaderParser headerParser(){ return new HeaderParser(); } @Bean public HeaderGenerator headerGenerator(){ return new HeaderGenerator(); } } -
导入
ImportSelector接口的实现类@Import({MyImportSelector.class}) @SpringBootApplication public class SpringBootWeb{ }MyImportSelector的内容为
public class MyImportSelector implements ImportSelector{ public String[] selectImports(AnnotationMetadata importingClassMetadata){ //返回值封装的是全类名,这里就是将配置类交给IOC容器,然后一次性生成所有配置类里面的bean return new String[]{"com.example.HeaderConfig"}; } }
-
-
方案3:三方依赖提供一个
@EnableXxxx注解,里面封装@Import注解@EnableHeaderConfig注解@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Import(MyImportSelector.class) //通过import注解引入MyImportSelector //通过MyImportSelector引入HeaderConfig //通过HeaderConfig引入所有要交给IOC的bean public @interface EnableHeaderConfig{ }这种方案是Spring Boot所采取的方案
5.2 自动装配原理
SpringBoot的自动配置就是当Spring容器启动后,一些配置类、bean对象就自动存入到了lOc容器中,不需要我 们手动去声明,从而简化了开发,省去了繁琐的配置操作。其核心原理可以概括为:基于约定和条件注解,自动扫描并加载所需的 Bean 配置。
5.2.1 自动装配的核心机制
-
@EnableAutoConfiguration注解-
@SpringBootApplication注解组合了@EnableAutoConfiguration,用于启用自动配置。 -
@EnableAutoConfiguration通过SpringFactoriesLoader加载META-INF/spring.factories文件中定义的自动配置类。
-
-
条件化注解(Conditional Annotations)
Spring Boot 自动配置类使用条件注解判断是否生效,例如:
-
@ConditionalOnClass:当类路径存在某个类时生效。 -
@ConditionalOnMissingBean:当容器中不存在某个 Bean 时生效。 -
@ConditionalOnProperty:当配置文件中某个属性为特定值时生效。 -
@ConditionalOnWebApplication:当应用是 Web 应用时生效。
-
-
自动配置类的加载流程
-
启动类上的
@SpringBootApplication→ 触发@EnableAutoConfiguration -
``SpringFactoriesLoader
加载META-INF/spring.factories中所有org.springframework.boot.autoconfigure.EnableAutoConfiguration` 指定的类。 -
对每个自动配置类进行条件检查:
-
检查类路径是否存在所需依赖(如
DataSource.class)。 -
检查容器中是否已存在相关 Bean。
-
检查配置文件中的属性设置。
-
-
符合条件的配置类生效,向容器中注册 Bean。
-
5.2.2 源码追踪
-
@SpringBootApplication注解源码//元注解略 @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { //内容略 }-
@SpringBootConfiguration注解源码//元注解略 @Configuration//代表声明是一个配置类 @Indexed//加速应用启动的,不用管 public @interface SpringBootConfiguration { @AliasFor( annotation = Configuration.class ) boolean proxyBeanMethods() default true; }由此可以得出
@SpringBootApplication可以用来声明当前类是一个配置类,所以我们可以直接在启动类中编写三方Bean对象
-
-
@ComponentScan注解,用于组件扫描的,这个解释了为什么SpringBoot程序默认扫描启动类所在的包 -
@EnableAutoConfiguration注解,自动配置的核心注解@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage //可以看出导入的是ImportSelector接口的实现类 @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }-
AutoConfigurationImportSelector实现类源码public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { //1.这里指定了那些类要交给到IOC中 public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { //2.本质就是调用getAutoConfigurationEntry()方法来获取要导入的内容 AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } } //3.就是调用这个来获取要导入IOC容器的内容 protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //5.这个configurations是通过getCandidateConfigurations方法来获得到的 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.getConfigurationClassFilter().filter(configurations); this.fireAutoConfigurationImportEvents(configurations, exclusions); //4.看上面的getConfigurations可以知道我们需要知道configurations的内容 return new AutoConfigurationEntry(configurations, exclusions); } } //6.通过这个来获得configurations集合 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //因为返回的是这个集合,可以看到是通过loadFactoryNames方法来获取的 List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader())); ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add); //7.这个是断言,用来进行非空判断,如果是空的就返回提示信息 //这里可以看到如下俩个文件 //文件META-INF/spring.factories //文件:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports //8.可以知道,是通过加载这俩个文件的信息返回到configurations集合当中的 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; } }这个类实现了
DeferredImportSelector接口public interface DeferredImportSelector extends ImportSelector { //内容略 }DeferredImportSelector接口继承了ImportSelector
-
-
两个文件的位置
就是通过这个实现自动配置的,类似的Mybatis也用这种autoconfig的jar包
spring.factories文件内容,这个是早期用的大概2.7.x之前AutoConfiguration.imports文件内容,这个是Spring新版本用的
这些都是要加载的类的全类名,本质上就是读取这俩个文件然后加载到IOC容器之中
5.2.3 条件注解
并不是所有的bean都要加载到IOC容器当中的,是根据条件注解来根据条件来决定那些注解需要加载。
5.3 自定义starter
在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot 的 starter。
命名规范:
- 对于Spring官方提供的起步依赖命名规范都是:spring-boot-starter-XXX
- 对于三方主动整合Spring的起步依赖命名规范是:**xxx-**spring-boot-starter
自定义starter需要2个包
- autoconfigure包用来引入依赖
- starter包用来管理依赖
需求:自定义aliyun-Oss-spring-boot-starter,完成阿里云OSS操作工具类AliyunOSSUtils的自动配置。
目标:引入起步依赖引入之后,要想使用阿里云OSS,注入AliyunOSSUtils直接使用即可。
步骤:
-
创建
aliyun-oss-spring-boot-starter模块新建模块
修改模块的pom文件
删除多余的文件
-
创建
aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块新建模块
修改模块的pom文件
删除多余的文件
在starter中引入autoconfig依赖
-
在
aliyun-Oss-spring-boot-autoconfigure模块中的定义自动配置功能,并定义自动配置文件META-INF/spring/xxxx.imports在starter中引入阿里云OSS相关依赖
在starter引入Spring相关依赖
编写AliOSSProperties
@ConfigurationProperties(prefix= "aliyun.oss") public class AliOSSProperties{ private String endpoint; private String accessKeyId; private String accessKeySecret; private String bucketName; //get和set方法 //构造方法 }编写AliOSSUtils
public class AliOSSUtils{ private AliOSSProperties aliOSSProperties; /** 实现上传图片到OSS */ public String upload(MultipartFile file) throws IOException{ //获取阿里云OSS参数 String endpoint=aliOSSProperties.getEndpoint(); String accessKeyId=aliOSSProperties.getAccessKeyId(); String accessKeySecret=aliOSSProperties.getAccessKeySecret(); String bucketName=aliOSSProperties.getBucketName(); //获取上传文件的输入流 InputStream inputStream=file.getInputStream(); //避免文件覆盖 String originalFileName= file.getOriginalFilename(); String fileName= UUID.randomUUID().toString() + originalFileName.substring(originalFileName.lastIndexOf()) //上传文件到OSS OSS ossClient = new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret); ossClient.putObject(bucketName,fileName,inputStream); //文件访问路径 String url=endpoint.split("//")[0] + "//"+bucketName+"."+endpoint.split("//")[1]+"/"; //关闭ossClient ossClient.shutdown(); //把上传到oss的路径返回 return url; } }编写AliOSSAutoConfiguration
@Configuration @EnableConfigurationProperties(AliOSSProperties.class) public class AliOSSAutoConfiguration{ @Bean public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties){ AliOSSUtils aliOSSUtils= new AliOSSUtils(); aliOSSUtils.setAliOSSProperties(aliOSSProperties); return aliOSSUtils; } }在resources目录下创建如下目录
在文件中写入配置类的全类名
com.aliyun.oss.AliOSSAutoConfiguration