Spring 易错点整理
一、@SpringBootApplication 的组成
@SpringBootApplication 是一个组合注解,由以下三个注解合成:
| 注解 | 作用 |
|---|---|
@SpringBootConfiguration(内含 @Configuration) | 标记当前类为 Spring 配置类 |
@EnableAutoConfiguration | 开启自动配置(核心) |
@ComponentScan | 扫描 @Component、@Service、@Repository、@Controller 等 |
⚠️ 易错:说成
@Configuration+@AutoConfiguration+@ComponentScan。正确的是@SpringBootConfiguration+@EnableAutoConfiguration+@ComponentScan,注意拼写。
二、自动配置原理
执行流程
@SpringBootApplication
↓
@EnableAutoConfiguration
↓
AutoConfigurationImportSelector(核心加载器)
↓
读取配置文件
├── 2.7 之前 → META-INF/spring.factories
└── 2.7+ → META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
↓
逐条解析 @Conditional 条件注解(满足才加载)
↓
满足条件的配置类 → 生效 → 初始化对应 Bean
⚠️ 易错:
spring.factories说成spring.factory(缺 s)@EnableAutoConfiguration拼成@AutoConfiguration- 不知道 2.7+ 配置文件位置已变更
三、条件注解体系
| 注解 | 生效条件 |
|---|---|
@ConditionalOnClass | 类路径中存在指定类才加载(如 classpath 有 DataSource 才加载数据库自动配置) |
@ConditionalOnMissingBean | 容器中没有该 Bean 才加载(用户自定义可覆盖默认) |
@ConditionalOnProperty | 配置项满足指定值才加载(如 spring.redis.enabled=true) |
@ConditionalOnBean | 容器中存在指定 Bean 才加载 |
@ConditionalOnWebApplication | 当前项目是 Web 应用才加载 |
⚠️ 易错:笼统说成
@OnClassBean,应该具体说出 2~3 个名字并举例。
四、AOP 核心概念
| 概念 | 说明 | 对应注解 |
|---|---|---|
| Aspect(切面) | 切面 = 切点 + 通知,将横切逻辑模块化 | @Aspect |
| Pointcut(切点) | 定义"在哪些方法上"织入增强逻辑 | @Pointcut |
| Advice(通知) | 定义"什么时候执行"增强逻辑 | @Before、@After、@Around 等 |
五种通知类型
┌── @Before ──┐
▼ ▼
┌─────────────────────────┐
│ 目标方法执行 │
└─────────────────────────┘
▲ ▲
└─ @AfterReturning ┘(正常返回)
└─ @AfterThrowing ┘(异常返回)
└─── @After ───────┘(最终)
@Around = @Before + @After + 可控制目标方法是否执行
⚠️ 易错:
- 把
@Aspect拼成@Aspect/@Aspect?- 说
@Around定义切点(❌)→@Pointcut定义切点,@Around是通知类型(✅)
五、JDK 动态代理 vs CGLIB
| 对比项 | JDK 动态代理 | CGLIB |
|---|---|---|
| 原理 | 基于接口,生成实现同一接口的代理对象 | 基于继承,生成目标类的子类 |
| 要求 | 必须实现接口 | 不能是 final 类 / final 方法 |
| 核心类 | InvocationHandler + Proxy | MethodInterceptor + Enhancer |
| Spring Boot 2.x+ 默认 | ❌ 不默认 | ✅ 默认 |
Spring Boot 2.x 的默认代理选择
目标 Bean 有接口吗?
├── proxy-target-class=false → JDK 动态代理
└── proxy-target-class=true(默认)→ CGLIB
⚠️ 易错:还在说 "Service 用 JDK,配置类用 CGLIB"?这是 Spring Boot 1.x 的老黄历了。Spring Boot 2.x+ 默认全部使用 CGLIB(
spring.aop.proxy-target-class=true),不管有没有接口。
为什么 Spring Boot 2.x 改默认?
- 统一行为:不用再考虑有没有接口
- 不会漏代理:没接口的 Bean 也能正常代理
- CGLIB 自身也在进步:性能差距已很小
原创
spring易错
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法