本文写于 2017 年 3 月——Spring Boot 2.0 即将发布、Spring Cloud Netflix 全家桶正盛。
一、Spring 7 大组件
1.1 核心组件
| 组件 | 作用 |
|---|
| 核心容器(Spring Core) | 提供 IoC 和依赖注入(DI)特性 |
| Spring 上下文(Spring Context) | BeanFactory 功能加强的子接口 |
| Spring AOP | 面向切面编程,AOP 联盟兼容 |
| Spring DAO | JDBC 抽象层,简化 JDBC 编码 |
| Spring ORM | 整合 Hibernate / MyBatis 等 ORM 框架 |
| Spring Web | Web 应用开发支持 |
| Spring MVC | MVC 思想的 Web 实现 |
1.2 面试追问
Q1:Spring 3 大核心思想?
- IoC(Inversion of Control):控制反转,对象的创建和依赖关系由 Spring 容器管理
- DI(Dependency Injection):依赖注入,通过构造器 / Setter / 字段注入
- AOP(Aspect-Oriented Programming):面向切面编程
二、IoC 原理
2.1 IoC 容器核心接口
1
2
3
4
5
| BeanFactory(基础容器)
└─ ApplicationContext(增强容器)
├─ ClassPathXmlApplicationContext
├─ AnnotationConfigApplicationContext
└─ WebApplicationContext
|
2.2 Bean 生命周期
1
| 实例化(构造器)→ 属性注入 → 初始化前回调 → 初始化方法 → 初始化后回调 → 使用 → 销毁前回调 → 销毁
|
关键回调接口:
| 接口 | 方法 | 用途 |
|---|
BeanFactoryPostProcessor | postProcessBeanFactory | 容器刷新前修改 Bean 定义 |
BeanPostProcessor | postProcessBeforeInitialization | 初始化前增强 |
BeanPostProcessor | postProcessAfterInitialization | 初始化后增强 |
InitializingBean | afterPropertiesSet | 初始化回调 |
DisposableBean | destroy | 销毁回调 |
2.3 Bean 作用域
| 作用域 | 描述 | 适用 |
|---|
| singleton | 单例(默认) | 无状态 Bean |
| prototype | 多例 | 有状态 Bean |
| request | 每个 HTTP 请求 | Web 应用 |
| session | 每个 HTTP Session | Web 应用 |
| application | 整个 ServletContext | 全局共享 |
三、AOP 原理
3.1 过滤器 vs 拦截器 vs AOP
| 维度 | 过滤器(Filter) | 拦截器(Interceptor) | AOP |
|---|
| 拦截对象 | URL | URL | 类的元数据(包/类/方法/参数) |
| 时机 | 请求到达 | 控制器前后 | 方法执行前后 |
| 粒度 | 粗 | 中 | 细 |
| 容器 | Servlet | Spring MVC | Spring |
执行顺序:过滤器 → 拦截器 → AOP
3.2 AOP 失效场景
场景 1:内部方法直接调用
1
2
3
4
5
6
7
8
9
| @Component
public class MyBean {
public void methodA() {
methodB(); // 这里会绕过代理!
}
@Transactional
public void methodB() { /* 业务 */ }
}
|
原因:Spring AOP 基于动态代理,内部方法直接调用不走代理。
解决方案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| // 1. AopContext.currentProxy(不推荐,代码侵入)
@EnableAspectJAutoProxy(exposeProxy = true)
public class MyApp { /* ... */ }
// methodA 中:
((MyService) AopContext.currentProxy()).methodB();
// 2. 自我注入(推荐)
@Service
public class MyService {
@Autowired
@Lazy
private MyService self;
public void methodA() {
self.methodB();
}
}
// 3. 提取到新 Bean(最优雅)
@Service
public class OrderTransactionExecutor {
private final TransactionTemplate transactionTemplate;
public void executeInTransaction(NonSpringTask task) {
transactionTemplate.execute(status -> {
task.doDbWork();
return null;
});
}
}
|
场景 2:new 出来的对象
1
2
3
| // 错误:new 出来的对象,aop 无法代理
NonSpringTask task = new NonSpringTask();
task.doDbWork(); // 事务不生效
|
解决:用 Spring 容器管理,或在 new 出的对象内部用 TransactionTemplate。
场景 3:异步方法 @Async
1
2
| @Async
public void asyncMethod() { /* 异步执行 */ }
|
坑点:
- 异步方法不能在同类内部调用(同样不走代理)
- 异步方法抛异常无法被 Controller 捕获
- 异步方法需要 public 修饰
- 异步方法所在的类需要
@EnableAsync 或被扫描
四、Spring Boot 自动配置原理
4.1 启动入口
1
2
3
4
5
6
| @SpringBootApplication // = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
|
4.2 自动配置机制
SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。
自 Spring Boot 3.0 开始,自动配置包的路径从 META-INF/spring.factories 修改为 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。
4 大步骤:
- 启动类加
@SpringBootApplication - 注解触发
@EnableAutoConfiguration EnableAutoConfiguration 导入 AutoConfigurationImportSelector- 该 Selector 扫描
META-INF/spring.factories 中的 EnableAutoConfiguration 全限定名列表 - 加载所有
XxxAutoConfiguration 类 - 每个 AutoConfiguration 类用
@Conditional 系列注解控制是否生效
4.3 关键注解
| 注解 | 作用 |
|---|
@ConditionalOnClass | 类路径存在某类时生效 |
@ConditionalOnMissingBean | 容器没有某 Bean 时生效 |
@ConditionalOnProperty | 配置项满足条件时生效 |
@ConditionalOnWebApplication | Web 应用时生效 |
@ConditionalOnBean | 容器有某 Bean 时生效 |
4.4 Starter 原理
在 SpringBoot 启动时由 @SpringBootApplication 注解会自动去 maven 中读取每个 starter 中的 spring.factories 文件,该文件里配置了所有需要被创建 spring 容器中的 bean,并且进行自动配置把 bean 注入 SpringContext 中。
自定义 Starter 4 步:
- 创建
xxx-spring-boot-starter 工程 - 引入 Spring Boot 相关依赖
- 创建
XxxAutoConfiguration - 在
META-INF/spring.factories 注册
4.5 启动时执行代码
方式 1:ApplicationRunner / CommandLineRunner
1
2
3
4
5
| @Bean
@Order(1)
public ApplicationRunner myRunner() {
return args -> System.out.println("复杂参数:" + Arrays.toString(args.getSourceArgs()));
}
|
方式 2:CommandLineRunner(简单参数)
1
2
3
4
| @Bean
public CommandLineRunner myRunner() {
return args -> System.out.println("简单参数:" + Arrays.toString(args));
}
|
方式 3:ApplicationListener<ApplicationReadyEvent>
1
2
3
4
5
6
7
| @Bean
public ApplicationListener<ApplicationReadyEvent> readyListener() {
return event -> {
// Spring Boot 完全就绪后
// 可获取 environment
};
}
|
三种方式对比:
| 方式 | 用途 | 时机 |
|---|
CommandLineRunner | 简单启动逻辑 | Spring 启动完成 |
ApplicationRunner | 复杂启动逻辑 | Spring 启动完成 |
ApplicationListener<ApplicationReadyEvent> | 完全就绪后执行 | Web 服务器就绪后 |
@PostConstruct | 单个 Bean 初始化 | Bean 注入完成 |
InitializingBean | 单个 Bean 初始化(更安全) | Bean 注入完成 |
五、Spring Boot 常用注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| @SpringBootApplication // 核心注解
@SpringBootConfiguration // = @Configuration
@EnableAutoConfiguration // 打开自动配置
@ComponentScan // 组件扫描
@Repository // DAO 组件
@Service // Service 组件
@RestController // = @Controller + @ResponseBody
@ResponseBody // 返回值写入 response body
@Component // 泛指组件
@Bean // 产生 Bean
@Autowired // byType 自动装配
@Qualifier("name") // 指定 Bean 名称
@Resource // byName 自动装配
@RequestMapping // URL 映射
@RequestParam // 请求参数
@Scope // Bean 作用域
@Primary // 优先选择
@PostConstruct // 初始化回调
@PreDestroy // 销毁回调
@EnableTransactionManagement // 启用注解事务
@Transactional // 声明事务
@ControllerAdvice // 全局异常处理
@ExceptionHandler // 异常处理
|
六、Spring Cloud Gateway
6.1 简介
Spring Cloud Gateway 是一个构建于 Spring Framework 5、Project Reactor 和 Spring Boot 2 之上的动态、可编程的 API 网关。
6.2 核心特点
- 基于路由的 API 网关:根据预定义路由转发请求
- 集成断言和过滤器:声明式路由控制
- 响应式编程支持:内部使用 WebFlux
- 服务发现集成:Eureka / Consul / Nacos
- 断路器集成:Hystrix / Sentinel / Resilience4J
- 安全集成:Spring Security + OAuth2 + JWT
- CORS 支持
- 全局过滤器:日志、限流
- 动态路由:不重启更新路由
6.3 三大组成
| 组成 | 描述 |
|---|
| Route(路由) | 路由的基本模块,由 ID、目标 URI、断言集、过滤器集组成 |
| Predicate(断言) | 访问该路由的访问规则,匹配 headers / 参数等 |
| Filter(过滤器) | 在请求/响应前后修改内容 |
6.4 优点
- 基于非阻塞和异步的 Netty + Spring WebFlux
- 高吞吐量 + 高并发
- 声明式路由规则
- 与 Spring 生态无缝集成
- 原生 WebSocket 支持
- 易于扩展
七、Spring Cloud 组件对比
| 组件 | Spring Cloud Netflix | Dubbo | Spring Cloud Alibaba |
|---|
| 服务中心 | Eureka / Consul | ZK | Nacos |
| 配置中心 | Spring Cloud Config | - | Nacos |
| 远程调用 | Feign | gRPC | Feign |
| API 网关 | Zuul / Gateway | - | Gateway / Apisix |
| 分布式事务 | - | - | Seata |
| 熔断器 | Hystrix | - | Sentinel / Resilience4j |
| 限流降级 | Hystrix | - | Sentinel |
| 分布式追踪 | Sleuth + Zipkin | - | SkyWalking |
7.1 三大断路器对比
| 维度 | Sentinel | Hystrix(维护状态) | Resilience4j(Spring 推荐) |
|---|
| 开发者 | Alibaba | Netflix | 独立 |
| 隔离策略 | 信号量隔离 | 线程池/信号量 | 信号量 |
| 熔断策略 | 响应时间 / 异常比率 / 异常数 | 异常比率 | 异常比率 / 响应时间 |
| 实时统计 | 滑动窗口(LeapArray) | 滑动窗口(RxJava) | Ring Bit Buffer |
| 限流 | 基于 QPS + 调用关系 | 有限 | Rate Limiter |
| 控制台 | 开箱即用 | 简单 | 需对接 |
Sentinel 核心特性:
- 流量控制(QPS / 并发线程数)
- 熔断降级(响应时间 / 异常数)
- 系统负载保护
- 实时监控
- 完善 SPI 扩展点
八、CAP 原则
CAP 原则:Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
| 维度 | 含义 |
|---|
| 一致性 | 所有数据备份在同一时刻是否同样的值 |
| 可用性 | 集群一部分节点故障后,集群整体还能响应 |
| 分区容忍 | 实际效果而言,分区相当于对通信的时限要求 |
8.1 注册中心 CAP 选择
| 注册中心 | CAP |
|---|
| Eureka | AP(可用性 + 分区容忍) |
| ZooKeeper | CP(一致性 + 分区容忍) |
| Nacos | AP + CP(可切换) |
Nacos 配置:
1
2
3
4
5
| spring:
cloud:
nacos:
discovery:
ephemeral: false # false: 持久化实例,使用 CP 架构;true: 临时实例,使用 AP 架构
|
九、写在最后
Spring 面试要点:
- 基础:IoC 原理、Bean 生命周期、Bean 作用域
- AOP:失效场景(内部调用 / new 对象 / 异步方法)
- Spring Boot:自动配置原理、Starter、自定义 Starter
- Spring Cloud:Gateway 三大组成、Sentinel / Nacos 选型、CAP 原则
- 高频追问:“AOP 失效怎么办”、“Starter 怎么写”、“服务挂了怎么限流”
参考资料