news 2026/5/16 14:20:04

Spring boot相关

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring boot相关

1.

问题1:为什么扫描的是 com.example.demo 包?

因为主入口类在这个包下。
com.example.demo ├── DemoApplication.java ← 主入口类在这个包
├── HelloController.java ← 同包,能被扫描到 ✓
├── sub/
│ ├── SomeService.java ← 子包,也能被扫描到

@ComponentScan 的默认规则:从主入口类所在的包开始,往下扫描所有子包。不会往上层扫,也不会扫其他包。

所以如果把 HelloController 移到 com.other 包下,Spring Boot 就找不到它了——除非你手动配置扫描范围。

问题2:"带注解的类"怎么理解?

注解可以标在类上,也可以标在方法上,它们是不同的东西

@RestController // ← 类注解:标注在类定义上方,描述"这个类是什么角色"
public class HelloController {

@GetMapping("/") // ← 方法注解:标注在方法上方,描述"这个方法怎么处理请求"
public String hello() {
return "Hello";
}
}

Spring Boot 扫描时是分层理解的:

1. 先看类上的注解 → 决定"这个类要不要管"
- 看到 @RestController → 这是一个控制器,我要注册它
- 没有类注解 → 普通类,不管它
2. 再看方法上的注解 → 在已经"管"的类内部,进一步细化
- 看到 @GetMapping("/") → 把这个方法和路由 "/" 绑定

所以类注解是第一层筛选——如果一个类上没有任何 Spring 注解,Spring Boot 直接跳过它,里面的方法注解也不会被看。

问题3:Spring Boot 启动时会扫描所有类吗?

不会扫描所有类,只扫描指定包下的类。

具体流程是这样的:

Spring Boot 启动

确定扫描起点:主入口类所在的包 (com.example.demo)

遍历这个包及所有子包下的 .class 文件

对每个类,检查类上有没有 Spring 相关注解:

有 @RestController → 注册为控制器
有 @Service → 注册为服务层
有 @Repository → 注册为数据层
有 @Component → 注册为通用组件
有 @Configuration → 注册为配置类

没有任何 Spring 注解 → 跳过,不管它

完成扫描,启动 Tomcat,准备接收请求

所以不是所有类都会被扫描到,也不是扫描到的类都会被注册——只有在指定包下 + 类上有 Spring 注解的类才会被纳入管理。

扫描到的类会被创建成单例对象,存进 Spring 容器,全局共用

2.

@Component — 通用员工

当一个类不属于上面各层任何一种角色,但又需要被 Spring 管理,就用 @Component:

职责:辅助工具类,不是核心业务角色,但大家都会用到它。

为什么要有这些区分?

如果所有类都用同一个注解,Spring Boot 就不知道每个类该承担什么职责。区分角色后:

1. 职责清晰:每个类只干自己的事
2. 方便管理:Spring Boot 可以对不同角色做不同处理(比如 Controller 自动注册路由)
3. 团队协作:前端工程师改 Controller,数据库工程师改 Repository,互不干扰

ps:

对于后端工程师来说,Service 确实是写得最多、改得最多的,因为业务逻辑最复杂、变化最频繁。但 Controller (API定义)和 Repository(数据库操作)
也是后端工程师的职责——后端工程师负责整个后端,不只是某一层

3.

对比项 @ComponentScan 扫描 @Bean 方法

适用场景自己写的类 (可以自己加注解)第三方库的类、需特殊配置的对象(不能对源码加注解


创建方式 Spring 自动调用构造方法 你手动 new 或调用工厂方法

能否传参 不能,只能默认构造 可以,自由传参配置

进入容器 都一样,存进去全局共用 都一样

第2条路:@Bean 方法(现在讲的) @Configuration public class AppConfig { @Bean // ← 标记这个方法的返回值要存入容器 public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); // 手动创建对象 } } 这条路适合第三方库的对象——你没法给第三方类加 @Service 注解,所以只能用 @Bean 手动创建并存入容器。 详细过程 @ComponentScan 扫描到 AppConfig 类 ↓ 发现类上有 @Configuration → 这是一个配置类,我要仔细看它 ↓ 遍历里面的方法,找所有带 @Bean 注解的方法 ↓ 找到 passwordEncoder() 方法 ↓ 调用这个方法,拿到返回值:new BCryptPasswordEncoder() ↓ 把这个对象存入容器: 容器.put("passwordEncoder", BCryptPasswordEncoder实例) ↓ 以后任何地方需要 PasswordEncoder,直接从容器取,不用自己 new

4.依赖注入

"依赖注入"拆开理解: - 依赖:UserService 需要 PasswordEncoder 才能干活,这个需求就叫"依赖" - 注入:不需要你自己创建,由 Spring 从外部"注入"(塞进来)给你 传统方式(手动创建依赖): UserService 自己 new PasswordEncoder → 自己解决依赖 依赖注入方式: Spring 把 PasswordEncoder 注入到 UserService 中 → 外部帮你解决依赖 所以**@Autowired(自动装配) = "帮我注入依赖"**,它就是依赖注入机制的一个注解标记。 Spring 中的三种注入方式 除了字段上加 @Autowired,还有另外两种写法: 1. 字段注入(最常见,你一直在看的) @Service public class UserService { @Autowired private PasswordEncoder encoder; // 直接在字段上标注 } 2. 构造器注入(推荐的方式) @Service public class UserService { private final PasswordEncoder encoder; @Autowired // 标在构造方法上 public UserService(PasswordEncoder encoder) { this.encoder = encoder; // 构造时就注入 } } Spring 创建 UserService 时,调用构造方法,把容器中的 PasswordEncoder 作为参数传进来。 3. Setter 注入 @Service public class UserService { private PasswordEncoder encoder; @Autowired // 标在 setter 方法上 public void setEncoder(PasswordEncoder encoder) { this.encoder = encoder; } } Spring 创建 UserService 后,调用 setter 方法把对象传进来。

实际开发中推荐构造器注入,因为:
- 可以把字段设为 final,注入后不可变,更安全
-依赖关系在构造时就确定,不会出现"对象创建了但依赖还没注入"的问题
- 不加 @Autowired 也能工作(Spring 4.3+ 只有一个构造方法时自动注入)

// 推荐写法:省略 @Autowired 也能自动注入
@Service
public class UserService {
private final PasswordEncoder encoder;

public UserService(PasswordEncoder encoder) { // 自动注入
this.encoder = encoder;
}
}

5. 如何理解继承自parent可以避免依赖版本冲突 ?

假设你的项目依赖了 A 和 B 两个库,而它们各自又依赖了不同版本的 C: 你的项目 ├── 库A(需要 C 1.0) ├── 库B(需要 C 2.0) 问题来了:两个版本的 C 都想被加载,但 JVM 只能用一个版本。 如果你用了 C 1.0,库B 可能报错;用了 C 2.0,库A 可能报错——这就是版本冲突。 你自己手动指定版本的话,要搞清楚每个库依赖了什么版本的 C,极其麻烦: <!-- 你得自己研究:到底该用哪个版本?? --> <dependency> <groupId>com.example</groupId> <artifactId>C</artifactId> <version>1.0 还是 2.0??</version> </dependency> 有 parent 后怎么解决 spring-boot-starter-parent 内部预定义了几百个依赖的版本号,这些版本都是 Spring 团队测试过、确认互相兼容的: 所以你写依赖时不用写版本号: <!-- 没有 parent → 你必须指定版本,可能选错 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>??? 我该写啥 ???</version> </dependency> <!-- 有 parent → 版本号由 parent 统一管理,不用你写 --> <dependency>

6. Maven仓库管理

Maven 的**仓库(Repository)**就是存放依赖 jar 包的地方,分三种:

1. 本地仓库(在你电脑上) - 默认路径:C:\Users\你的用户名\.m2\repository

- Maven 下载的 jar 包都存在这里,项目引用时从这里取 - 只下载一次,后续项目复用,不用重复下载

2. 中央仓库(在互联网上)
- Maven 官方维护,地址:repo.maven.apache.org
- 几乎所有开源库都在这里,本地仓库没有时自动从这里下载

3. 私有仓库(公司内部)
- 大公司自建,存放内部私有 jar 包
- 需要在 pom.xml 里额外配置地址

工作流程很简单:

项目需要一个jar → 先查本地仓库 → 没有就从中央仓库下载到本地 → 用本地那份

7. 日志管理

Spring Boot 项目中日志配置统一放在 src/main/resources 目录下

:logback-spring.xml 独立配置文件(现在用的) 放在 src/main/resources/logback-spring.xml,功能完整,可以自定义 appender、格式、滚动策略等。 Spring Boot 加载日志配置的优先级: 1. logback-spring.xml(推荐,支持 Spring 特有功能) 2. logback.xml(纯 Logback 配置,不支持 Spring profile 等) 3. application.properties 中的 logging.* 配置(最简单,功能最少) 如果你的 logback-spring.xml 存在,它就是主配置,application.properties 中的 logging.* 设置会被忽略。所以现在你项目里日志的完整控制权在 logback-spring.xml,所有日志相关配置改这一个文件就行。

8. 前端——中间件——后端架构

Tomcat 不是"再交给" Spring Boot,而是内嵌在 Spring Boot 里面的。 它们不是两个独立的东西接力,而是同一个进程: 前端请求 → Nginx → Spring Boot应用(内嵌Tomcat) ↓ Tomcat接收HTTP请求 ↓ Spring MVC路由分发 ↓ 映射到HelloController方法处理 ↓ ↓ 返回响应 传统部署方式(Spring Boot之前): 独立Tomcat服务器 → 部署war包到里面 → Tomcat + 应用是分离的 Spring Boot方式: Tomcat打包进jar → java -jar demo.jar 一键启动 → Tomcat和应用是一体的 所以简单说:Nginx转发给Spring Boot,Spring Boot自己内部就包含了Tomcat来处理请求。

9.yaml配置的优点

properties格式 — 平铺,每行一个配置: server.port=8080 spring.application.name=demo logging.level.root=info logging.file.name=app.log yaml格式 — 层级缩进,树状结构: server: port: 8080 spring: application: name: demo logging: level: root: info file: name: app.log

- 功能完全相同,没有谁更强
- Spring Boot都支持,优先级一样(同时存在时properties优先)
- 可以互相转换,挑一种用就行

实际项目中yaml更主流,因为配置多了之后层级一目了然,不用反复写前缀。你当前项目用的是properties,配置少所以没什么差别,想换yaml随时可以。

10.

相同配置按优先级加载,不同配置可以同时生效

11.

松散绑定(去掉分隔符,全转为小写字母来进行匹配)只适用于@ConfigurationProperties@Value 不支持。@Value("${app.greeting-prefix}") 必须和 yaml 里的 key 完全一致。

12.

整合 JUnit是因为 Spring 项目里对象之间有依赖注入关系,普通测试拿不到完整的对象,必须启动 Spring 容器才行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/16 14:15:07

Midscene.js:如何用AI视觉技术实现跨平台自动化测试的终极指南

Midscene.js&#xff1a;如何用AI视觉技术实现跨平台自动化测试的终极指南 【免费下载链接】midscene AI-powered, vision-driven UI automation for every platform. 项目地址: https://gitcode.com/GitHub_Trending/mid/midscene 在当今多平台应用爆炸式增长的时代&am…

作者头像 李华
网站建设 2026/5/16 14:13:31

明日方舟MAA助手:如何用5分钟自动化你的每日游戏任务

明日方舟MAA助手&#xff1a;如何用5分钟自动化你的每日游戏任务 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手&#xff0c;全日常一键长草&#xff01;| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: https://gitc…

作者头像 李华
网站建设 2026/5/16 14:10:02

3分钟搞定鼠标连点器:解放双手的自动化神器

3分钟搞定鼠标连点器&#xff1a;解放双手的自动化神器 【免费下载链接】MouseClick &#x1f5b1;️ MouseClick &#x1f5b1;️ 是一款功能强大的鼠标连点器和管理工具&#xff0c;采用 QT Widget 开发 &#xff0c;具备跨平台兼容性 。软件界面美观 &#xff0c;操作直观&a…

作者头像 李华
网站建设 2026/5/16 14:09:32

异步复位同步释放:数字电路稳定性的核心设计原理与实践

1. 项目概述&#xff1a;一个看似简单却暗藏玄机的设计细节在数字电路设计&#xff0c;尤其是FPGA和ASIC的前端设计工作中&#xff0c;异步复位同步释放&#xff08;Asynchronous Reset Synchronous Release&#xff0c; 简称ASYNC_RST_SYNC_RELEASE&#xff09;是一个高频出现…

作者头像 李华