知其然要知其所以然,探索每一个知识点背后的意义,你知道的越多,你不知道的越多,一起学习,一起进步,如果文章感觉对您有用的话,关注、收藏、点赞,有困惑的地方请评论,我们一起交流!
一、Spring IOC 实现原理与适用场景
1. 实现原理
IOC(控制反转)是 Spring 的核心机制,通过容器管理对象的生命周期和依赖关系。其核心实现包括:
-
容器结构
基于BeanFactory和ApplicationContext接口,容器通过BeanDefinition存储 Bean 元数据(类路径、作用域、初始化方法等),在启动时解析配置(XML/注解)并注册 Bean 定义。 -
依赖注入方式
- 构造器注入:通过反射调用构造函数,强制依赖初始化。
- Setter 注入:通过 JavaBean 规范调用 setter 方法。
- 注解注入:
@Autowired基于类型匹配,结合@Qualifier指定名称。
-
Bean 生命周期
- 实例化(反射调用构造函数)
- 属性填充(依赖注入)
BeanPostProcessor.postProcessBeforeInitialization- 初始化方法(
@PostConstruct或init-method) BeanPostProcessor.postProcessAfterInitialization- 销毁阶段(
@PreDestroy或destroy-method)
-
作用域管理
Singleton(单例池缓存)、Prototype(每次创建新对象)、Request/Session(Web 环境)等。
2. 适用场景
- 解耦与可测试性
通过依赖注入实现组件解耦,方便 Mock 测试。 - 复杂依赖管理
自动处理循环依赖(通过三级缓存:singletonFactories、earlySingletonObjects、singletonObjects)。 - 统一资源配置
集中管理数据库连接池、线程池等资源。 - 动态配置切换
结合 Profile(@Profile)实现多环境配置切换。
二、Spring AOP 实现原理与适用场景
1. 实现原理
AOP(面向切面编程)通过动态代理实现横切关注点的模块化:
-
代理机制
- JDK 动态代理:基于接口(
Proxy.newProxyInstance),生成实现目标接口的代理类。 - CGLIB 代理:通过继承目标类生成子类(
Enhancer),覆盖方法实现增强。
- JDK 动态代理:基于接口(
-
织入过程
- 解析
@Aspect注解类,生成Advisor(包含 Pointcut 和 Advice)。 - 在 Bean 初始化阶段,通过
AbstractAutoProxyCreator创建代理对象。 - 匹配方法执行时,通过责任链模式调用拦截器链(
MethodInterceptor)。
- 解析
-
核心概念实现
- Pointcut:通过
AspectJExpressionPointcut解析表达式(如execution(* com.service.*.*(..)))。 - Advice 类型:
@Before:方法前插入代码。@AfterReturning:方法正常返回后执行。@Around:通过ProceedingJoinPoint.proceed()控制目标方法执行。@AfterThrowing:异常处理。@After(finally 块逻辑)。
- Pointcut:通过
2. 适用场景
- 日志记录
统一记录方法入参、返回值、耗时(通过@Around计算时间差)。 - 事务管理
@Transactional基于 AOP 实现,通过TransactionInterceptor管理事务边界。 - 权限校验
在方法执行前进行角色/权限检查(@Before+ 抛出异常拦截)。 - 性能监控
统计方法调用次数、成功率等指标(结合 Metrics 库)。 - 缓存控制
通过@Cacheable在方法执行前检查缓存,减少重复计算。
三、IOC 与 AOP 的协同工作
- AOP 代理对象的创建依赖 IOC
代理对象由BeanPostProcessor(如AnnotationAwareAspectJAutoProxyCreator)在 Bean 初始化阶段生成。 - AOP 切面本身是 IOC 管理的 Bean
@Aspect类需被 Spring 容器扫描,其依赖可通过 IOC 注入。 - 解决自我调用问题
同类方法内部调用无法被 AOP 拦截(因绕过代理),可通过AopContext.currentProxy()获取当前代理对象。
四、典型应用对比
| 技术 | 典型场景 | 实现复杂度 | 性能影响 |
|---|---|---|---|
| IOC | Bean 依赖管理、多环境配置 | 低(声明式配置) | 启动时开销,运行时无影响 |
| AOP | 日志/事务等横切逻辑 | 中(需设计切点表达式) | 每次方法调用增加代理逻辑 |
五、总结与选型建议
- 优先使用 IOC 的场景
- 需要集中管理对象依赖关系。
- 需实现组件替换(如不同数据库实现)。
- 优先使用 AOP 的场景
- 多个模块需要相同横切逻辑(如安全审计)。
- 不希望业务代码被非功能代码污染。
- 避免滥用
- 简单场景无需过度设计(如仅单个方法需要日志可不使用 AOP)。
- 高频调用方法需谨慎使用 AOP,避免性能损耗。