SpringBoot原理详解

本文详细探讨了SpringBoot的配置优先级,包括properties、yml、yaml文件,以及Java系统属性和命令行参数。此外,还深入解析了SpringBoot的Bean管理,涵盖Bean的获取、作用域以及如何处理第三方Bean。最后,文章阐述了SpringBoot的起步依赖和自动配置原理,分析了自动配置的实现机制和@Conditional注解的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpingBoot原理详解

springboot原理详解,主要偏向于底层原理,深挖SpringBoot的底层实现原理.

1. 配置优先级

SpringBoot项目当中支持三类配置文件,分别是*.properties文件,.yml文件,.yaml文件:

  • application.properties
  • application.yml
  • application.yaml

在SpringBoot项目当中,我们要想配置一个属性,可以通过这三种方式当中的任意一种来配置都可以,那么如果项目中同时存在这三种配置文件,且都配置了同一个属性,如:Tomcat端口号,到底哪一份配置文件生效呢?

  • application.properties
server.port=8081
  • application.yml
server:
   port: 8083
  • application.yaml
server:
   port: 8082

我们启动SpringBoot程序,测试下三个配置文件中哪个Tomcat端口号生效:

  • properties、yaml、yml三种配置文件同时存在

配置优先级

properties、yaml、yml三种配置文件,优先级最高的是properties

  • yaml、yml两种配置文件同时存在

请添加图片描述

根据上面两次的测试,我们得出结论,配置文件优先级排名(从高到低):

  1. properties配置文件
  2. yml配置文件
  3. yaml配置文件

注意事项:虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置。(yml是主流)

在SpringBoot项目当中除了以上3种配置文件外,SpringBoot为了增强程序的扩展性,除了支持配置文件的配置方式以外,还支持另外两种常见的配置方式:

  1. Java系统属性配置 (格式: -Dkey=value)

    -Dserver.p
    

ort=9000


2. 命令行参数 (格式:--key=value)

~~~shell
--server.port=10010

那在idea当中运行程序时,如何来指定Java系统属性和命令行参数呢?

  • 编辑启动程序的配置信息
    !

请添加图片描述
在这里插入图片描述

重启服务,同时配置Tomcat端口(三种配置文件、系统属性、命令行参数),测试哪个Tomcat端口号生效:

在这里插入图片描述

删除命令行参数配置,重启SpringBoot服务:
在这里插入图片描述

根据以上测试我们得出优先级: 命令行参数 > 系统属性参数 > properties参数 > yml参数 > yaml参数

如果项目已经打包上线了,这个时候我们又如何来设置Java系统属性和命令行参数呢?

java -Dserver.port=9000 -jar XXXXX.jar --server.port=10010

下面我们来演示下打包程序运行时指定Java系统属性和命令行参数:

  1. 执行maven打包指令package,把项目打成jar文件
  2. 使用命令:java -jar 方式运行jar文件程序

项目打包:
请添加图片描述
请添加图片描述
运行jar程序:

  • 同时设置Java系统属性和命令行参数

请添加图片描述
可以看到启动时端口号为10010

  • 仅设置Java系统属性

请添加图片描述

注意事项:

  • Springboot项目进行打包时,需要引入插件 spring-boot-maven-plugin (基于官网骨架创建项目,会自动添加该插件)

总结:在SpringBoot项目当中,常见的属性配置方式有5种, 3种配置文件,加上2种外部属性的配置(Java系统属性、命令行参数)。通过以上的测试,我们也得出了优先级(从低到高):

  • application.yaml(忽略)
  • application.yml
  • application.properties
  • java系统属性(-Dxxx=xxx)
  • 命令行参数(–xxx=xxx)
    官方文档解释:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-build-systems

2. Bean管理

我们可以通过Spring当中提供的注解@Component以及它的三个衍生注解(@Controller、@Service、@Repository)来声明IOC容器中的bean对象.

2.1 获取Bean

默认情况下,SpringBoot项目在启动的时候会自动的创建IOC容器(也称为Spring容器),并且在启动的过程当中会自动的将bean对象都创建好,存放在IOC容器当中。应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以了。

在Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象,下面介绍3种常用方式:

  1. 根据name获取bean

    Object getBean(String name)
    
  2. 根据类型获取bean

    <T> T getBean(Class<T> requiredType)
    
  3. 根据name获取bean(带类型转换)

    <T> T getBean(String name, Class<T> requiredType)
    

要从IOC容器当中来获取到bean对象,需要先拿到IOC容器对象,想获取到IOC容器,直接将IOC容器对象注入进来就可以了

控制器:DeptController

@RestController
@RequestMapping("/depts")
public class DeptController {
   
   

    @Autowired
    private DeptService deptService;

    public DeptController(){
   
   
        System.out.println("DeptController constructor ....");
    }

    @GetMapping
    public Result list(){
   
   
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id)  {
   
   
        deptService.delete(id);
        return Result.success();
    }

    @PostMapping
    public Result save(@RequestBody Dept dept){
   
   
        deptService.save(dept);
        return Result.success();
    }
}

业务实现类:DeptServiceImpl

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {
   
   
    @Autowired
    private DeptMapper deptMapper;

    @Override
    public List<Dept> list() {
   
   
        List<Dept> deptList = deptMapper.list();
        return deptList;
    }

    @Override
    public void delete(Integer id) {
   
   
        deptMapper.delete(id);
    }

    @Override
    public void save(Dept dept) {
   
   
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.save(dept);
    }
}

Mapper接口:

@Mapper
public interface DeptMapper {
   
   
    //查询全部部门数据
    @Select("select * from dept")
    List<Dept> list();

    //删除部门
    @Delete("delete from dept where id = #{id}")
    void delete(Integer id);

    //新增部门
    @Insert("insert into dept(name, create_time, update_time) values (#{name},#{createTime},#{updateTime})")
    void save(Dept dept);
}

测试类:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
   
   

    @Autowired
    private ApplicationContext applicationContext; //IOC容器对象

    //获取bean对象
    @Test
    public void testGetBean(){
   
   
        //根据bean的名称获取
        DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
        System.out.println(bean1);

        //根据bean的类型获取
        DeptController bean2 = applicationContext.getBean(DeptController.class);
        System.out.println(bean2);

        //根据bean的名称 及 类型获取
        DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
        System.out.println(bean3);
    }
}

程序运行后控制台日志:

在这里插入图片描述

问题:输出的bean对象地址值是一样的,说明IOC容器当中的bean对象有几个?

答案:只有一个。 (默认情况下,IOC中的bean对象是单例)

问题:那么能不能将bean对象设置为非单例的(每次获取的bean都是一个新对象)?

答案: 可以

注意事项

  • 上述所说的 【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。

2.2 Bean作用域

在前面我们提到的IOC容器当中,默认bean对象是单例模式(只有一个实例对象)。那么如何设置bean对象为非单例呢?需要设置bean的作用域。

在Spring中支持五种作用域,后三种在web环境才生效:

作用域 说明
singleton 容器内同名称的bean只有一个实例(单例)(默认)
prototype 每次使用该bean时会创建新的实例(非单例)
request 每个请求范围内会创建新的实例(web环境中)
session 每个会话范围内会创建新的实例(web环境中)
application 每个应用范围内会创建新的实例(web环境中)

知道了bean的5种作用域了,我们要怎么去设置一个bean的作用域呢?

  • 可以借助Spring中的@Scope注解来进行配置作用域

请添加图片描述
1). 测试一

  • 控制器
//默认bean的作用域为:singleton (单例)
@Lazy //延迟加载(第一次使用bean对象时,才会创建bean对象并交给ioc容器管理)
@RestController
@RequestMapping("/depts")
public class DeptController {
   
   

    @Autowired
    private DeptService deptService;

    public DeptController(){
   
   
        System.out.println("DeptController constructor ....");
    }

    //省略其他代码...
}
  • 测试类
@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
   
   

    @Autowired
    private ApplicationContext applicationContext; //IOC容器对象

    //bean的作用域
    @Test
    public void testScope(){
   
   
        for (int i = 0; i < 10; i++) {
   
   
            DeptController deptController = applicationContext.getBean(DeptController.class);
            System.out.println(deptController);
        }
    }
}

重启SpringBoot服务,运行测试方法,查看控制台打印的日志:

在这里插入图片描述

可以看到控制台打印的是同一个实例

注意事项:

  • IOC容器中的bean默认使用的作用域:singleton (单例)

  • 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)

2). 测试二

修改控制器DeptController代码:

### SpringBoot 自动装配原理深入解析 SpringBoot 的自动装配机制是其核心特性之一,它通过一系列注解和配置文件实现了开箱即用的功能。以下是对其工作原理的详细分析: #### 1. **核心注解** `@EnableAutoConfiguration` 是自动装配的核心注解[^3]。它的作用是对 Spring ApplicationContext 进行自动化配置,尝试猜测并注册应用程序可能需要的 Bean。具体来说,该注解会扫描类路径中的依赖项,并根据这些依赖项加载相应的配置。 ```java @Configuration @ConditionalOnClass({ Servlet.class }) @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { } ``` - `@Configuration`: 表明这是一个配置类。 - `@ConditionalOnClass`: 只有当指定的类存在于类路径中时,才会生效。 - `@Import(AutoConfigurationImportSelector.class)`: 导入了一个名为 `AutoConfigurationImportSelector` 的类,用于决定哪些自动配置类应该被应用。 --- #### 2. **自动配置的选择逻辑** `AutoConfigurationImportSelector` 类负责处理自动配置类的选择过程。它主要依据以下几个方面完成任务: - **META-INF/spring.factories 文件**: 在每个 Starter 组件中,都会提供一个 `spring.factories` 文件,其中定义了一系列候选的自动配置类。例如,在数据库相关的 Starter 中可能会包含如下内容: ```properties org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration ``` - **条件化装配 (Condition-based Configuration)**: 每个自动配置类都带有特定的条件注解(如 `@ConditionalOnClass`, `@ConditionalOnMissingBean`),只有满足这些条件时,对应的 Bean 才会被创建。这使得 SpringBoot 能够灵活适应不同的运行环境。 --- #### 3. **复合注解的作用** 除了单独使用 `@EnableAutoConfiguration` 外,通常还会配合其他注解一起使用,比如 `@SpringBootApplication`。实际上,`@SpringBootApplication` 就是一个复合注解,包含了以下三个部分[^4]: - `@SpringBootConfiguration`: 定义当前类为一个配置类[^5]。 - `@EnableAutoConfiguration`: 启用自动配置功能。 - `@ComponentScan`: 开启组件扫描,以便发现并注册项目中的 Bean。 因此,开发者只需在一个主类上标注 `@SpringBootApplication` 即可实现完整的初始化流程。 --- #### 4. **实际案例演示** 假设我们需要快速搭建一个 Web 应用程序,则可以通过引入 Spring Boot Web Starter 来简化开发过程。下面展示如何利用自动装配构建一个简单的 RESTful API: ```java @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @RestController static class HelloController { @GetMapping("/hello") public String sayHello() { return "Hello, World!"; } } } ``` 在这个例子中,由于导入了 Spring Boot Web Starter,框架会自动检测到 Tomcat 和 DispatcherServlet 存在于类路径中,并相应地配置好嵌入式的 HTTP Server 和 MVC 支持。 --- #### 总结 SpringBoot 的自动装配机制极大地降低了传统 Spring 项目的复杂度,使开发者能够专注于业务逻辑而非繁杂的基础设置。通过对 `@EnableAutoConfiguration`、`AutoConfigurationImportSelector` 以及各种条件注解的学习,可以更好地掌握这一强大工具的工作方式。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岛森年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值