SpringBoot-快速入门

SpringBoot-快速入门

1

SpringBoot的环境要求

spring官网中的SpringBoot的参考文档中有写环境的要求,这里以SpringBoot-3.5.12版本为例说一下环境要求

2

环境&工具 版本(or later)
Java 17+
Spring Framework 6.2.17+
Maven 3.6.3 or later
Gradle Gradle 7.x(7.6.4 or later) or 8.x(8.4 or later)

SpringBoot是什么

SpringBoot是基于Spring生态的一个快速开发脚手架,用来简化Spring应用的搭建和开发,让你能写很少配置、直接运行一个生成级Java应用

SpringBoot的定义

官方定义:
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need minimal Spring configuration.

翻译为:
Spring Boot可以轻松创建独立的、基于Spring的生成级应用程序,让你"只需要运行"。我们对Spring平台和第三方库有自己的看法,这样你就可以轻松上手。大多数SpringBoot应用程序只需要很少的Spring配置。
  • 基于Spring生态:底层还是Spring Framework,只是在你和Spring之间加了一层"约定大于配置"的简化层
  • 独立可运行:打包成可执行jar,内嵌Tomcat/Jetty等Web服务器,不需要再部署到外部容器
  • 生产级:自带监控、健康检查、外部化配置等"生产就绪"特性
  • 开箱即用:通过场景启动器(starter)和自动配置,大幅减少样板配置和XML
可以将SpringBoot理解为:
SpringBoot = Spring + 约定 + 自动配置 + 内嵌容器 + 生产级特性

SpringBoot解决了什么问题

解决了传统Spring开发的典型痛点:

  • 配置繁琐:大量XML或Java配置,手动配置数据源、事务、MVC、安全等
  • 依赖管理麻烦:容易冲突,版本需要自己协调
  • 部署麻烦:需要打包成WAR,部署到Tomcat容器上
SpringBoot的目的就是尽量零配置,快速搭建一个可以直接运行,接近生产标准的应用

SpringBoot的特性

官方列出的特性如下:

  • Create stand-alone Spring applications:创建独立的Spring应用程序

  • Embed Tomcat,Jetty or Undertow directly(no need to deploy WAR files):直接嵌入Tomcat、Jetty、Undertow等Web服务器+Servlet容器(无需部署war包)

  • Provide opinionated 'starter' dependencies to simplify your build configuration:提供可选的starter(场景启动器)来简化应用配置

  • Automatically configure Spring and 3rd party libraries whenever possible:按需自动配置Spring以及第三方依赖

  • Provide production-ready features such as metrics,health checks,and externalized configuration:提供生产级特性如监控指标、健康检查、外部化配置等

  • Absolutely no code generation and no requirement for XML configuration:绝对无代码生成,不需要XML配置

注:
springboot为每一个场景提供了一个依赖即场景启动器(starter),比如web场景的依赖:spring-boot-starter-web

如果引入了对应的依赖即对应的场景,那么这个场景的所有配置都会自动配置好。对应场景会有默认的配置(约定大于配置),也可以通过配置文件来修改默认配置(自定义)

快速构建SpringBoot项目

构建SpringBoot项目示例

1.指定父POM

所有springboot项目都必须继承自 spring-boot-starter-parent

    <!-- 所有springboot项目都必须继承自 spring-boot-starter-parent -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.9</version>
    </parent>

2.子模块导入web场景和SpringBoot打包插件

    <dependencies>
        <!-- web开发的场景启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <!-- SpringBoot应用打包插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3.主启动类

/**
 * 启动springboot项目的主入口程序
 */
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

4.控制层接口

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello spring boot";
    }
}

5.打包为jar包并运行

通过mvn命令构建jar包,并通过java -jar命令运行程序

6.测试接口

启动程序后访问网页:http://localhost:8080/hello

3

如果能够正常返回字符串如上图所示则表示快速构建的SprinBoot项目功能正常

示例中体现的特性

  1. 简化整合
导入相关的场景(场景启动器-starter),拥有相关的功能。
SpringBoot支持的场景可参见官方文档:
https://docs.spring.io/spring-boot/3.5/reference/using/build-systems.html#using.build-systems.starters

官方提供的场景命名方式: spring-boot-starter-*
第三方提供的场景命名方式: *-spring-boot-starter
  1. 简化开发
无需编写任何配置,直接开发业务
  1. 简化配置
application.properties配置文件:
集中式管理配置,只需要修改这一个文件即可
配置基本都有默认值
能编写的所有配置可参见官方文档:
https://docs.spring.io/spring-boot/3.5/appendix/application-properties/index.html
  1. 简化部署
打包为可执行的jar包
  1. 简化运维
修改配置不需要重新打包,修改外部的application.properties文件即可

使用Spring Initializr 一键构建SpringBoot项目

Spring Initializr是Spring官方提供的一个基于Web的项目生成工具

核心配置项

  • Project Metadata(项目元数据)
    • Group:项目组名
    • Artifact:项目名称
    • Name:项目显示名称
    • Packaging:打包方式:Jar(微服务/独立运行),War(传统部署到外部Tomcat)
    • Java Version:JDK版本
  • Dependencies(依赖选择):在勾选SpringBoot版本后会根据版本自动匹配最兼容的依赖版本

常见的三种构建方式

方式一:通过官网页面构建项目

官方Spring Initializr页面:https://start.spring.io/

4

在配置好参数和依赖后点击下方的GENERATE按钮后,会从浏览器中下载一个.zip的压缩包

方式二:通过IDEA集成构建项目

IDEA内置了对Spring Initializr的支持

5

6

在IDEA中点击新建项目,选择Spring Initializr后填写项目元数据与依赖后点击Creat后完成构建

方式三:通过命令行

Spring Initializr本质上暴露了RESTful API,可以通过命令行直接生成

# 使用 curl 调用 API 生成项目
curl https://start.spring.io/starter.zip -d type=maven-project -d language=java -d bootVersion=3.1.0 -d baseDir=demo -d groupId=com.example -d artifactId=demo -d name=demo -d dependencies=web,mybatis,mysql -o demo.zip

SpringBoot的常用注解

SpringBoot是注解驱动优先,并且默认情况下不强制你写任何XML配置文件

组件(Bean)注册注解

声明配置类的注解(@Configuration和@SpringBootConfiguration)

@SpringBootConfiguration注解上面直接标注了@Configuration。
在Spring容器看来,一个类上标了@SpringBootConfiguration等同于标了@Configuration。

@SpringBootConfiguration和@Configuration的作用完全一样:告诉Spring,这是一个配置类,里面可能有@Bean注解,请把这个类作为配置元数据来解析。

这两个配置类的区别主要是语义不同,为的是划清"阵营"的界限:
@Configuration是Spring Framework(核心框架)的注解,从Spring3.0就已存在,属于底层基础。
@SpringBootConfiguration是SpringBoot的注解,专门为SpringBoot服务。

日常使用中手写配置类只用@Configuration,@SpringBootConfiguration留给框架和底层去使用

管理对象创建和生命周期的注解(@Bean和@Scope)

@Bean

在全注解时代,@Bean的作用就是完美替代XML中标签

作用位置:写在配置类里面的方法上
作用:告诉Spring: 请调用这个方法,把方法返回的对象拿走,注册到Spring容器中,以后有人要这个对象,直接从容器中拿,不用自己new了
@Scope

@Bean注解默认时单例的(全局唯一),但如果每次想要一个全新的对象就需要@Scope

作用位置:写在方法上(配合@Bean使用),也可以写在类上(配合@Component使用)
作用:指定该Bean的作用域(生命周期范围)
常见的作用域:
singleton:默认值,整个Sping容器中只有一个实例。适用于工具类、Service、DAO、配置类等绝大多数情况。
prototype:原型,每次向Spring要这个对象,Spring都会给你new一个全新的。适用于有状态的对象(比如每次请求需要不同的连接、任务对象)。
request:请求,在一次HTTP请求中有效,不同请求拿到不同的实例。仅在Web环境中有效。
session:会话。再一次HTTP Session中有效。仅在Web环境中有效。
application:应用。在一个ServletContext生命周期内有效。仅在Web环境中有效。

将对象自动注册到Spring容器的注解(@Component,@Controller,@Service,@Repository)

@Component、@Controller、@Service、@Repository这四个注解的效果是相同的,都是把这个类示例化成一个单例Bean。它们在底层本质上完全一样,唯一的区别是为了语义化分层。

@Controller(控制层/表现层)
@Controller(控制层/表现层)
角色:系统的"门面"。负责接收前端发来的HTTP请求,提取参数,调用Service处理业务,最后把结果返回给前端。
位置:通常放在类上,类名以xxController结尾。
注:在SpringBoot开发中,一般用该注解的升级版本@RestController,专门用于直接返回JSON数据。
@Controller + @ResponseBody = @RestController
@Service(业务逻辑层)
角色:系统的"大脑"。负责处理具体的业务逻辑。
位置:通常放在类上,类名以xxService或xxServiceImpl结尾。
@Repository(持久层/数据访问层)
角色:系统的"手脚"。专门负责和数据库打交道。
位置:通常放在类上,类名以xxDao,xxMapper,xxRepository结尾。
注:Spring为@Repository配置了一个特殊的后置处理器:它能自动捕获底层数据库抛出的特定异常,并将它们统一转换为spring体现下的DataAccessException异常。这意味着业务层不需要catch具体的数据库异常,只需要catch Spring的通用异常即可,实现了业务代码与底层数据库技术的解耦。
@Component(通用组件)
角色:"杂牌军"收容所。当一个类不属于上述角色中的任意一种且需要被Spring管理,就用@Component。
常见场景:工具类、自定义拦截器、过滤器、跨切面的通用处理类。

包扫描和显示导入的注解(@ComponentScan和@Import)

如果说Spring容器是一个"大仓库",那么@ComponentScan和@Import就是往仓库里面"进货"的两种截然不同的方式,@ComponentScan和@Import都是把类变成Spring容器里面的Bean,但是两者的工作机制完全相反

@ComponentScan: 自动发现与扫描
工作机制:它依赖与Spring的类路径扫描器。它会在底层遍历你指定的目录下的所有.class文件,然后检查这些类的字节码上有没有@Component(以及它派生注解@Controller、@Service、@Repository)。有就实例化,没有就跳过。

特点:
被动发现:不需要知道具体有多少个类,只要它们符合"贴了标签"的规则,就会被自动找出来。
受限于包路径:它只能扫描你指定的basePackages及其子包。超出这个范围(比如其他Jar包的类),就无法生效。

注:在SpringBoot中很少手动写@ComponentScan,因为@SpringBootApplication这个复合注解默认内置了@ComponentScan,并且默认扫描范围是该启动类所在的包及其子包。
@Import: 显示导入与注册
工作机制:它不扫描文件系统,就是单纯地把你注解中写死的哪些Class对象,直接塞到Spring注册表。哪怕这个类上没有任何注解,只有写在@Import中,它就能变成Bean。

特点:
主动精准:指定类,需要谁进谁就进。
无视包路径限制:可以跨Jar包导入。
无视注解限制:可以导入没有@Component的普通类,甚至可以通过ImportSelector动态导入。
@ComponentScan和@Import的使用场景
@ComponentScan用来管理自身的业务代码,@Import用来导入第三方库和框架底层。一内一外构建Spring容器的强大的对象管理能力

组件注册注解使用示例

引入依赖
    <!-- 所有springboot项目都必须继承自 spring-boot-starter-parent -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.9</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.27</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>    
    <!-- SpringBoot应用打包插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
POJO类
public class User {
    private Long id;
    private String name;

    public String getName() {
        return name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }
}
配置类
//替代之前的配置类 -普通配置类用@Configuration,springboot配置类用@SpringBootConfiguration
//@Configuration
//给容器中放入指定类型的组件,组件名称默认为全类名
@Import(FastsqlException.class)
@SpringBootConfiguration
public class AppConfig {

    @Bean("userAlex")
    /**
     * 替代配置类之前的properties标签
     * 组件在容器中名称默认为方法名,也可以在@Bean注解进行修改
     */
    @Scope("prototype")
    /**
     * 替代配置类之前的scope标签
     * 默认为单实例singleton,多实例为prototype
     */
    public User getUserOne() {
        User user = new User();
        user.setId(1L);
        user.setName("alex");
        return user;
    }

//    @Bean
//    public FastsqlException fastsqlException() {
//        return new FastsqlException();
//    }
}
主启动类
/**
 * 启动springboot项目的主入口程序
 *
 * 主程序包 com.shen.annotations
 * 可以使用@ComponentScan或@SpringBootApplication中的scanBasePackages属性来指定扫描路径
 */
//@ComponentScan("com.shen.annotations")
@SpringBootApplication(scanBasePackages = "com.shen.annotations")
@SpringBootApplication
public class CommonAnnoationsApplication {
    public static void main(String[] args) {
        //获取spring容器
        var ioc = SpringApplication.run(CommonAnnoationsApplication.class, args);
        String[] names = ioc.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("========================================");
        String[] types = ioc.getBeanNamesForType(User.class);
        for (String type : types) {
            System.out.println(type);
        }

        Object userOne = ioc.getBean("userAlex");
        Object userTwo = ioc.getBean("userAlex");
        System.out.println(userOne == userTwo);
        System.out.println("========================================");
        String[] type1 = ioc.getBeanNamesForType(FastsqlException.class);
        for (String type : type1) {
            System.out.println(type);
        }
    }
}

条件注解(@ConditionalOnXxx)

SpringBoot的核心设计理念之一就是"约定大于配置",而实现这一理念背后的关键技术就是条件注解

条件注解运行开发者根据特定的条件来决定是否注册Bean或执行某些配置。这极大地实现了SpringBoot的自动装配功能,即只有在满足特定条件时,组件才会被加载。由于@ConditionOnXxx系列注解较多这里只说明类条件注解和Bean条件注解,其他条件注解可以参见官网:

https://docs.spring.io/spring-boot/3.5/reference/features/developing-auto-configuration.html#features.developing-auto-configuration.condition-annotations

类条件注解

这类注解用于判断特定的类是否存在于classpath(类路径)中

@ConditionalOnClass
  • 含义:当给定的类名在类路径中存在时,匹配成功
  • 场景:当你需要依赖某个第三方库时,例如:只有在项目中引入了Jackson库,才配置JSON序列化器
ConditionalOnMissingClass
  • 含义:当给定的类名在类路径中不存在时,匹配成功
  • 场景:通常用于提供默认实现。如果用户没有引入某个类,则使用默认的简单实现

Bean条件注解

这里注解用于判断容器中是否存在特定的Bean

@ConditionalOnBean
  • 含义:当Spring容器中存在指定的Bean时,匹配成功
  • 场景:依赖注入,例如:只有当存在DataSource Bean时,才创建JdbcTemplate
@ConditionalOnMissingBean
  • 含义:当Spring容器不存在指定的Bean时,匹配成功
  • 场景:这是自动配置中最常用的注解。它允许开发者覆盖默认配置。如果开发者自己定义了一个Bean,SpringBoot的默认Bean就不会生效

条件注解示例

POJO类
public class Cat {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Dog {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
条件配置类
/**
 * 条件注解演示场景-@ConditionalOnXX
 * 如果存在
 * FastsqlException
 * 这个类,给容器中放⼀个Cat组件,名为 catOne,
 * 否则,就给容器中放⼀个Dog组件,名为dogOne
 * 如果系统中有dogOne这个组件,就给容器中放⼀个 User组件,名userDog
 * 否则,就放⼀个User组件,名叫userNoDog
 */
@Configuration
public class ConditionalConfig {

    @Bean(name = "catOne")
    @ConditionalOnClass(name = "com.alibaba.druid.FastsqlException")
    public Cat getCat() {
        return new Cat();
    }

    @Bean(name = "dogOne")
    @ConditionalOnMissingClass(value = "com.alibaba.druid.FastsqlException")
    public Dog getDog() {
        return new Dog();
    }

    @Bean(name = "userDog")
    @ConditionalOnBean(name = "dogOne")
    public User getUserDog() {
        return new User();
    }

    @Bean(name = "userNoDog")
    @ConditionalOnMissingBean(name = "dogOne")
    public User getUserNoDog(){
        return new User();
    }
}
启动类
@SpringBootApplication
public class CommonAnnoationsApplication {
    public static void main(String[] args) {
        var ioc = SpringApplication.run(CommonAnnoationsApplication.class, args);
        String[] names = ioc.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }        System.out.println("=================conditional=======================");
        String[] dogType = ioc.getBeanNamesForType(Dog.class);
        for (String type : dogType) {
            System.out.println(type);
        }
        String[] catType = ioc.getBeanNamesForType(Cat.class);
        for (String type : catType) {
            System.out.println(type);
        }
    }
}

属性绑定注解

在SpringBoot中,@ConfigurationProperties和@EnableConfigurationProperties是实现类型安全配置的核心搭档。它们解决了使用@Value注解在配置项过多时代码臃肿、无法复用、不支持复杂对象校验等问题

  • @ConfigurationProperties:负责搬运,将配置文件中键值对映射到Java Bean的属性上
  • @EnableConfigurationProperties:负责注册,告诉Spring容器去识别并管理这个搬运工Bean

@ConfigurationProperties(配置绑定)

这个注解通常标注在POJO(Plain Old Java Object)类上,用于将外部配置(如application.yml或application.properties)绑定到类的字段上

注解特性:

  1. 前缀匹配:通过prefix或value指定配置的前缀
  2. 松散绑定:支持多种命名风格。例如配置文件中的user.first-name、user.firstName、user.first_name都可以映射到Java类中的firstName字段
  3. 类型转换:自动将字符串转换为对应的数据类型(如:Integer、Long、Date等)
  4. JSR-303校验:支持@Validated注解,配合@NotNull,@Email等进行配置校验

@EnableConfigurationProperties(启用注册)

此注解用于激活标注了@ConfigurationProperties的类,使其成为一个Spring容器管理的Bean

通常,为了让Spring识别一个类,我们会加上@Component。但在自动配置场景下,或为了保持POJO的纯粹性(不污染业务代码),我们不想在POJO上加@Component。此时就需要在一个配置类中使用@EnableConfigurationProperties来显式注册

属性绑定注解示例

POJO类
/**
 * 属性绑定注解-@ConfigurationProperties,既可以在对应类中绑定也可以在配置类中绑定
 */
//@Component
//@ConfigurationProperties(prefix = "pig")
public class Pig {
    private Long id;
    private String name;
    private String age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Pig{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}
@ConfigurationProperties(prefix = "sheep")
public class Sheep {
    private Long id;
    private String name;

    @Override
    public String toString() {
        return "Sheep{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
配置类
//@EnableConfigurationProperties:开启sheep组件的属性绑定并默认把这个组件放到容器中,主要用于导入第三方写好的组件进行属性绑定
//springboot默认只扫描自己主程序所在的包。如果导入了第三方包,即使组件上标注了@Componment、@ConfigurationProperties注解也没用,因为组件都扫描不进来
@EnableConfigurationProperties(Sheep.class)
@SpringBootConfiguration
public class AppConfig {
    /**
     * 属性绑定注解-@ConfigurationProperties,既可以在对应类中绑定也可以在配置类中绑定
     */
    @Bean
    @ConfigurationProperties(prefix = "pig")
    public Pig getPig() {
        return new Pig();
    }
}

配置文件
server:
  port: 8080
pig:
  id: 1
  name: 佩奇
  age: 5
sheep:
  id: 1
  name: 苏西
启动类
@SpringBootApplication
public class CommonAnnoationsApplication {
    public static void main(String[] args) {
        var ioc = SpringApplication.run(CommonAnnoationsApplication.class, args);
        String[] names = ioc.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("=================config bind=======================");
        Pig pig = ioc.getBean(Pig.class);
        System.out.println(pig);
        Sheep sheep = ioc.getBean(Sheep.class);
        System.out.println(sheep);
    }
}

YAML配置文件

YAML是一种人类可读的数据序列化语言。它全程是"YAML Ain't Markup Language",这强调它关注数据本身,而非文档标记(如HTML)

YAML设计理念

YAML的设计目标是让人们容易阅读和编写。它结合了XML的数据描述能力、Python的简洁语法以及C语言的转义习惯,非常适合来做配置文件、数据交换格式或日志文件。

在SpringBoot中,YAML已经称为了比传统properties文件更受欢迎的配置方式。它利用YAML的层级结果,完美契合了SpringBoot复杂的配置需求。

YAML语法特点

  • 大小写敏感
  • 使用缩进表示层级关系-- k: v,使用空格分割k,v
  • 缩进时不允许使用Tab键,只允许使用空格(一般推荐2个空格),缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • "#"表示注释,从这个字符一直到行尾,都会被解析器忽略
  • 数据类型丰富:原生支持标量(字符串、整数、浮点数)、列表、映射
    • 对象:键值对的集合,如:映射(map)、哈希(hash)、字典(dictionary)
    • 数组:一组按次序排列的值,如序列(sequence)、列表(list)
    • 纯量:单个的、不可再分的值,如字符串、数组、bool、日期

YAML使用示例

pom依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--lombok简化JavaBean开发,自动生成构造器、getter/seter、自动生成Builder模式等-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <!-- SpringBoot应用打包插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

POJO类

@Data
public class Cat {
    private String name;
    private Integer age;
}
@Data
public class Child {
    private String name;
    private Integer age;
    private Date birthday;
    /**
     * 字符串数组
     */
    private List<String> text;
}
@Data
public class Dog {
    private String name;
    private Integer age;
}
@Component
@Data
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Date birthday;
    private Boolean like;
    /**
     * 嵌套对象
     */
    private Child child;
    /**
     * 对象数组
     */
    private List<Dog> dogs;
    /**
     * kv键值对
     */
    private Map<String, Cat> cats;

}

YAML配置文件

# 1. k: v  # k v之前是空格区分 k:
# 2. 属性是有层级关系,使用下一行,空两个空格
# 3. 左侧对齐的代表同一层级的属性
# 4.大小写敏感

# birthDay推荐写为birth-day
# 单引号不会转义 ,双引号会转义 eg: \n
# 大文本,|开头,大文本并列写在下层,保留文本格式。>开头,大文本写在下层,压缩换行符换为空格
# 多文档合并,使用===可以把多个yaml文档合并在一个文件中,每个文档依然认为内容独立
server:
  port: 18089
spring:
  servlet:
    multipart:
      max-file-size: 1MB
---
person:
  name: 小明
  age: 24
  birthday: 2008/12/12 20:00:00
  like: true
  child:
    name: 小小明
    age: 5
    birth-day: 2020/8/8
#    text: ["a","b"]
    text:
      - |
        abcd
        defg
      - >
        1234
        5678
      - '123\n123'
      - "ab\nab"
  dogs:
    - name: 小白
      age: 1
    - name: 小黑
      age: 3
  cats:
    c1:
      name: 妙妙
      age: 5
    c2: {name: 叔, age: 3}

启动类

@SpringBootApplication
public class YamlApplication {
    public static void main(String[] args) {
        // java10: 局部变量类型自动推断
        var ioc = SpringApplication.run(YamlApplication.class, args);
        Person person = ioc.getBean(Person.class);
        System.out.println(person);
    }
}

日志配置

SpringBoot的日志体系非常强大且灵活,它内部默认使用了SLF4J(日志门面)+Logback(日志实现)的组合。在大多数情况下,开发者不需要引入额外的日志依赖即可直接使用

日志在日常中的使用

在代码中打印日志通常由两种方式

  1. 传统方式(手动创建Logger)
  2. 使用Lombok(推荐):引用Lombok,直接使用@Slf4j注解即可

SpringBoot是如何把日志默认配置好的

  • 每个starter场景,都会导入一个核心场景spring-boot-starter
  • 核心场景引入了日志的所用功能spring-boot-starter-logging
  • 默认使用了Logback+SLF4J组合作为底层日志
  • 日志是系统已启动就要用,xxAutoConfiguration是系统启动之后放好的组件,是后来用的。
  • 日志是利用监听器机制配置好的,ApplicationListener
  • 日志所有的配置都可以通过修改配置文件实现,以logging开始的所有配置

日志使用示例

pom依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--lombok简化JavaBean开发,自动生成构造器、getter/seter、自动生成Builder模式等-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <!-- SpringBoot应用打包插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

YAML配置文件

logging:
  pattern:
    # 控制台日志打印配置
    #    console: '%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{15} ===> %msg%n'
    # 单独配置日期打印格式
    dateformat: yyyy-MM-dd HH:mm:ss
  level:
    # 默认所有日志没有精确指定级别就使用root的默认级别
    root: info
    # 精确调整某个包下的日志级别
    com.shen.log.controller: info
    # 调整分组的日志级别
    abc: error
    # spring内置了两个分组,web请求方面,sql查询方面
    sql: trace
    web: trace
  # 日志分组,便于统一修改分组中的日志级别
  group:
    abc: com.shen.log.aaa,com.shen,com.aaa,com.bb
  # 指定日志的文件路径,日志文件默认叫spring.log
  file:
    # 指定日志文件的名可以只写名字也可以写路径+名字,因此name和path同时存在时只看name
    name: hello.log
    path: F:\\
  # 日志归档与切割 ,springboot默认整合logback,如果使用log4j2则需要添加log4j2.xml或log4j2-spring.xml
  logback:
    rollingpolicy:
      # 日志归档名称
      file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
      # 日志单文件最大空间
      max-file-size: 10MB
      # 日志文件被删除之前,可以容纳的最大大小,如果超过指定空间则会删除旧日志文件
      total-size-cap: 1GB
      # 日志文件保存的最大天数
      max-history: 7

控制层接口

@Slf4j
@RestController
public class HelloController {

    @GetMapping("/h")
    public String hello() {
//        Logger log = LoggerFactory.getLogger(HelloController.class);
//        log.info("/h请求进来了");
        log.info("/h请求进来了");
        return "hello";
    }

    @GetMapping("/test")
    public String testLog(String msg) {
        log.trace("trace日志---");
        log.debug("debug日志---");
        //springboot默认打印info级别及其以上级别日志
        log.info("info日志---msg: [{}]", msg);
        log.warn("warn日志---");
        log.error("error日志---");
        return "test";
    }
}

SpringBoot-依赖管理机制

SpringBoot的依赖管理机制使其核心特性之一,它极大地简化了构建配置,让开发者无需为依赖版本操心。其核心机制主要由"BOM(Bill of Materials-物料清单)"和"starter-场景启动器"两个概念支撑,底层通过Maven或Gradle的依赖管理插件实现

核心机制:父工程与BOM

spring-boot-starter-parent的继承

在传统的Maven项目中,我们需要手动指定每个依赖的版本。而在Spring Boot中,我们通常让项目继承spring-boot-starter-parent。它本身并没有包含实际的jar包,它是一个专门的POM文件,主要定义如下

  • 默认编译配置:例如Java编译版本(JDK17+)、编码格式(UTF-8)
  • 资源文件处理:如何处理application.properties或application.yml
  • 插件配置:配置了spring-boot-maven-plugin等插件
  • 最重要的:继承自spring-boot-dependencies

spring-boot-dependencies

spring-boot-starter-parent的父工程是spring-boot-dependencies,这才是Spring Boot依赖管理的真正核心

它是一个巨大的BOM文件,里面定义了几百个常用第三方库的号(如MySQL驱动、Jackson、Logback、Tomcat等),这里以spring-boot-dependencies-3.5.9.pom的部分截图作为展示:

7

机制原理:

当你在pom.xml中引入依赖时,如果不写<version>标签,Maven会向上查找父工程,最终在spring-boot-dependencies中找到预定义的版本。当然如果spring-boot-dependencies中没有的第三方依赖不写版本号会报找不到

实战场景:Starter机制

Spring Boot将常见的功能模块封装成Starter。Starter本质上时一个空的JAR,它只做一件事:传递依赖,这里以引入Web开发的starter为例

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

解析其过程:

  1. Maven解析spring-boot-starter-web.pom
  2. 该POM文件中定义了它所依赖的库如spirng-web,spring-webmvc,tomcat,jackson等
  3. 这些依赖的版本又通过父工程(BOM)统一管理

Starter机制的优点:

  • 一站式购物:引入一个Starter,自动引入该功能所需的所有依赖,避免了"漏依赖"或"依赖错"的问题
  • 版本兼容:Spring Boot团队已经测试过这些依赖之间的版本兼容性,确保它们能协同工作

特殊场景:不使用父工程

在某些企业级项目中,父工程可能被公司统一规定(如company-parent),无法继承spring-boot-start-parent。此时Spring Boot提供了另一种方式来引入依赖管理,通过dependencyManagement导入BOM

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.5.9</version>
            <type>pom</type>
            <scope>import</scope> <!-- 关键:import scope -->
        </dependency>
    </dependencies>
</dependencyManagement>

原理:

scop=import告诉Maven:将spring-boot-dependencies中<dependencyManagement>部分全部拷贝并合并到当前项目的<dependencyManagement>中,这样即使没有继承关系,也能享受到版本仲裁功能

版本覆盖与修改机制

虽然Spring Boot帮我们管理了版本,但如果确实需要使用特定版本(如旧版本的MySQL驱动),可以覆盖默认版本

方法一:直接指定版本(就近原则)

在当前项目pom.xml文件直接写上<version>。根据Maven的依赖调解原则-"就近原则",当前项目定义的版本优先级高于父工程定义的版本

方法二:修改属性(推荐)

spring-boot-dependencies将所有版本号都提取成了Maven属性,如果修改版本的依赖已被提取成Maven属性了,只需在自己pom.xml的<properties>中重写该属性即可

示例:修改mysql驱动版本

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <mysql.version>9.4.0</mysql.version>
    </properties>

    <dependencies>
        <!--maven就近原则-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <!--            <version>9.4.0</version>-->
        </dependency>
        <!-- 第三方依赖需要自行声明好,否则会报找不到 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.27</version>
            <scope>compile</scope>
        </dependency>
        <!-- web开发的场景启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

SpringBoot-自动配置机制

Spring Boot的自动配置机制是其"开箱即用"特性的核心灵魂。它旨在通过"约定大于配置"的思想,根据项目中的依赖和配置,自动推测并装配应用程序所需的Bean

Spring Boot会检测你的classpath下有什么jar包,然后自动帮你把相关的配置做好

核心入口:@SpringBootApplication

一切的起点都在启动类上的@SpringBootApplication注解。这个注解是一个组合注解,核心包含以下三个部分

8

  • @SpringBootConfiguration:表示这是一个配置类
  • @EnableAutoConfiguration:核心-开启自动配置
  • @ComponentScan:开启组件扫描

核心机制:@EnableAutoConfiguration的运作流程

这个注解通过@Import导入了一个关键的选择器:AutoConfigurationImportSelector,它作用流程如下:

9

1.加载候选配置类(读取文件)

当Spring Boot启动时,AutoConfigurationImportSelector会去读取classpath下所有的jar包中的特定文件。

特定文件路径为:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

在这个文件中列出来所有可能需要自动配置的类的全限定名

10

11

注:此时只是读取了名单,并没有真正创建Bean

2.条件过滤(按需装配)

拿到候选名单后,Spring Boot会根据一系列条件注解进行筛选。只有满足条件的配置类才会生效。这是自动配置最核心的逻辑

这里列举一些常见的条件注解:

条件注解 作用 示例
@ConditionalOnClass classpath中存在指定的类时生效 只有引入了spring-webmvc的包,WebMvcAutoConfiguration才生效
@ConditionalOnMissingBean 容器中不存在指定的Bean时生效 如果你自己定义了一个DataSource,Spring Boot就不会再自动配置默认的数据源
@ConditionalOnProperty 配置文件中存在特定属性时生效 只有在application.yml中配置了相关属性,才会触发某些配置
@ConditionalOnWebApplication 当前时Web应用时生效 只有在Web环境下才会配置Servlet相关的Bean

3.注册Bean

通过帅选的配置类会被Spring加载,配置类中通过@Bean注解定义的方法会被执行,从而将对象注入到Spring容器中

实战案例:HttpEncodingAutoConfiguration

以HTTP编码自动配置(HttpEncodingAutoConfiguration)为例,理解其工作原理

//这里仅截取了一小部分代码,实际该配置类没有这么少的代码
// 1.这是一个配置类
@AutoConfiguration
// 2.开启属性绑定
@EnableConfigurationProperties(ServerProperties.class)
// 3.必须是Servlet Web环境
@ConditionalOnWebApplication(type = Type.SERVLET)
// 4.必须存在这个类(引入了Spring Web依赖就存在)
@ConditionalOnClass(CharacterEncodingFilter.class)
// 5.配置文件中默认enabled=true
@ConditionalOnBooleanProperty(name = "server.servlet.encoding.enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    // 从配置文件中读取属性
	private final Encoding properties;

	public HttpEncodingAutoConfiguration(ServerProperties properties) {
		this.properties = properties.getServlet().getEncoding();
	}

	@Bean
    // 6.只有在容器中没有CharacterEncodingFilter时才创建
	@ConditionalOnMissingBean
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
		return filter;
	}
}
  1. Spring Boot读取到了这个配置类
  2. 检查:是不是Web项目?是的(引入了web-starter)
  3. 检查:有没有CharacterEncodingFilter类?有的(web-starter里面有)
  4. 检查:配置文件里面有没有禁用编码配置?默认没禁用
  5. 条件通过:Spring执行characterEncodingFilter方法,场景一个Bean并注入容器

用户自定义覆盖机制

Spring Boot的自动配置非常智能,它永远以用户的配置优先

这是通过@ConditionalOnMissingBean实现的。绝大多少自动配置类在定义@Bean时都会加上这个注解。

例如:

Spring Boot默认配置了一个ObjectMapper(用于JSON序列化)。如果你在代码中自己定义了一个ObjectMapper的Bean
@Bean
public ObjectMapper objectMapper() {
    // 自定义配置
    return new ObjectMapper();
}

Spring Boot在执行自动配置时,发现容器中已经有了ObjectMapper,就会跳过默认配置。这就是为什么我们只需要写少量代码就能覆盖默认行为的原因

属性绑定:配置文件如何生效?

自动配置类通常配合@EnableConfigurationProperties和@ConfigurationProperties使用

这里以ServerProperties属性类为例

12

先通过@ConfigurationProperties注解,将外部配置(如application.yml或application.properties)绑定到ServerProperties的字段上

13

之后用@EnableConfigurationProperties注解将ServerProperties类显示注册到容器中

参考资料

https://spring.io/projects/spring-boot#learn

https://www.bilibili.com/video/BV1Es4y1q7Bf/

posted @ 2026-04-03 20:26  柯南。道尔  阅读(3)  评论(0)    收藏  举报