Spring ioc aop 如何实现?
1 个回答
改变的秘密,是把所有的精力全放在新的事物上,而不是与过去抗衡。姬无双# IoC(控制反转)如何实现 本质:把“对象创建 + 依赖装配 + 生命周期管理”交给容器(`BeanFactory`/`ApplicationContext`)。 1. 元数据与容器 * 元数据:`BeanDefinition`(类名、作用域、依赖、初始化/销毁方法等)。 * 容器核心:`DefaultListableBeanFactory` 负责注册/保存 `BeanDefinition` 与创建 bean;`ApplicationContext` 在其上加事件、国际化、资源加载等。 2. 启动与扫描 * 注解/JavaConfig:`@ComponentScan` → `ClassPathBeanDefinitionScanner` 扫描出 `@Component/@Service/...` → 注册为 `BeanDefinition`。 * `@Configuration` 类会被 **CGLIB 增强**,以便拦截 `@Bean` 方法,保证从容器拿**同一单例**(`proxyBeanMethods=true` 时;Boot 常设为 false 提升启动性能)。 3. `getBean()` 创建流程(单例,含“三级缓存”) 简化关键路径(以 `Foo` 为例): * 查一级缓存 `singletonObjects`:有则直接返回。 * 无 → 标记“正在创建”,实例化(选构造器:`SmartInstantiationAwareBeanPostProcessor` 参与,比如 `@Autowired` 构造器)。 * 提前暴露“早期引用工厂”到**三级缓存** `singletonFactories`(用于解决循环依赖与生成代理的早期引用)。 * 属性注入(构造器/Setter/字段),解析 `@Autowired/@Qualifier` 等。 * 初始化回调:`Aware` 系列 → `BeanPostProcessor#postProcessBeforeInitialization` → `InitializingBean#afterPropertiesSet`/`@PostConstruct` → `postProcessAfterInitialization`(此步常产生**代理**)。 * 放入一级缓存,移除二/三级缓存,返回。 三级缓存要点(只对**单例**、且非构造器循环依赖有效): * ① `singletonObjects`:完全实例 * ② `earlySingletonObjects`:已实例化未完全初始化的“早期对象” * ③ `singletonFactories`:生成“早期引用”的工厂(AOP 可能在这里就返回代理,避免后续再替换) 4. 作用域与生命周期 * 作用域:`singleton`(默认)、`prototype`、`request/session`(Web)。 * 生命周期顺序(常见): 实例化 → 依赖注入 → Aware → `postProcessBeforeInitialization` → init → `postProcessAfterInitialization`(可能被代理)→ 使用 → destroy。 * `FactoryBean`:`getBean("&name")` 取工厂本身;`getBean("name")` 取其生产的对象。 # AOP(面向切面)如何实现 本质:**代理模式** + **方法拦截链**。Spring AOP 只做**方法级**织入(运行期),不是字节码替换(那是 AspectJ 的事)。 1. 自动代理的入口 * `AnnotationAwareAspectJAutoProxyCreator`(AAAPC)是一个 `BeanPostProcessor`,在 `postProcessAfterInitialization` 阶段: * 收集容器中所有 `Advisor`(`Pointcut`+`Advice`)。 * 匹配当前 bean 的方法是否命中切点(切点解析器支持 AspectJ 表达式)。 * 若命中,构造 `AdvisedSupport`,创建代理返回**替换原 bean**。 2. 代理的创建 * `DefaultAopProxyFactory` 决策: * 有接口 → `JdkDynamicAopProxy`(JDK 动态代理) * 否则/强制 → `CglibAopProxy`(CGLIB 生成子类;final 方法/类无法拦截) * 常见 Advice → 拦截器的适配: * `@Around` → `MethodInterceptor` * `@Before` → `MethodBeforeAdviceInterceptor` * `@AfterReturning` → `AfterReturningAdviceInterceptor` * `@AfterThrowing` → `ThrowsAdviceInterceptor` 3. 调用时发生什么(拦截链) * 代理对象的方法被调用 → 进入 `ReflectiveMethodInvocation` 拦截器链: * 逐个执行:`Around` → `Before` → 目标方法 → `AfterReturning`/`AfterThrowing` → `After` * 通过 `proceed()` 传递,链尾执行目标方法。 * 事务、缓存、权限等“声明式特性”都是**Advisor** 插入到这条链里完成的。 4. 易错点与实践 * **自调用失效**:同类内方法互调绕过代理(没有走拦截链)→ 解决:抽到别的 bean、或启用 `AopContext` 暴露代理后用 `((Foo)AopContext.currentProxy()).method()`。 * **final 方法/类**:CGLIB 无法拦截 final;JDK 代理只拦接口方法。 * **顺序**:用 `@Order`/`Ordered` 控制多个切面顺序。 * **事务增强点**:默认只拦 public 方法(`@Transactional`),且需通过代理调用才生效。 * **性能**:AOP 调用开销通常微小;热点高频核心路径尽量保持切面简单(少做 IO/日志大串)。 # 关键类速记(排查时好用) * IoC:`DefaultListableBeanFactory`、`AbstractAutowireCapableBeanFactory`、`BeanDefinition`、`BeanPostProcessor`、`BeanFactoryPostProcessor`、`AutowiredAnnotationBeanPostProcessor` * AOP:`AnnotationAwareAspectJAutoProxyCreator`、`Advisor/Pointcut/Advice`、`AdvisedSupport`、`JdkDynamicAopProxy/ObjenesisCglibAopProxy`、`ReflectiveMethodInvocation` # 小结 * IoC:以 `BeanDefinition` 为蓝图,由 `BeanFactory` 在 `getBean()` 时按“实例化→注入→后置处理→缓存”的链路创建/管理对象;三级缓存解决单例循环依赖,并与 AOP 的早期代理配合。 * AOP:`BeanPostProcessor` 在初始化后期给命中切点的 bean“换成代理”,调用时走**拦截器链**实现事务/日志/权限等横切关注点。发布于 2025-08-18 00:33 •IP属地 河南举报评论收藏
公众号进入网站体验更佳

