00-总结
spring事务的实现原理
- 1,解析切面:BeanFactoryPostProcess中执行解析。@EnableTransactionmanagement注解注册了一个配置类,配置类引入了adivsor。
- 2,创建动态代理:初始之后Bean的后置处理器。有接口使用JDK动态代理,没接口使用CGLIB动态代理。创建动态代理之前,需要先判断是否需要创建代理,是根据pointcut匹配的。判读方法上,类上,接口的方法上。
- 3,执行:
FactoryBean和BeanFactory的区别
FactoryBean的GetObject方法调用时机是:FactoryBean发生在属性填充(依赖注入)之后,FactoryBean但在初始化方法(@PostConstruct / InitializingBean)之前。所以FactoryBean的getObject() 方法返回的对象的实例化,对象的属性填充 需要自己在getObject() 方法中完成。而FactoryBean的自己的实例化和属性填充是正常的Bean。FactoryBean的getObject() 方法是不是相当于在容器中注册了2个Bean,一个FactoryBean对象,一个getObject() 方法返回的对象,但实际上,注册表(BeanDefinitionRegistry)中只有 FactoryBean 的 BeanDefinition,getObject() 返回的对象不会生成 BeanDefinition,它是在运行时通过 getObject() 动态创建并缓存在容器中的。
Bean的生命周期
不包含Spring解析注解转换为BeanDefinition的过程,是根据BeanDefinition创建Bean对象的过程。
实例化:根据BeanDefinition的Class信息,通过反射创建对象。
属性赋值:这个通过set方法完成赋值操作,更倾向于
@Auto和@Re的自定义的属性赋值检查Aware相关接口并设置依赖:这个更倾向容器对象的属性赋值,比如实现
ApplicationContextAware或者BeanFactoryAware初始化之前:BeanPostProcessor的后置处理postProcessBeforeInitialization()方法:
执行初始化方法:
@PostConstruct(注解) 执行自定义初始化逻辑(最常用)。InitializingBean(接口) 的afterPropertiesSet()方法 编程式初始化(接口方式)。@Bean(initMethod="xxx")指定初始化方法(XML或配置类方式)。初始化之前:BeanPostProcessor的后置处理postProcessAfterInitialization()方法,这里就是我们经常说对象代理的地方。
使用Bean对象
销毁Bean对象
| 执行时机 | 扩展接口 / 注解 | 核心方法 | 典型应用场景 |
|---|---|---|---|
| 1. 容器启动前 | BeanFactoryPostProcessor | postProcessBeanFactory() | 修改BeanDefinition元数据(如修改作用域、替换类名)。 执行时机非常早,在所有Bean实例化之前执行。 |
| 2. 实例化前 | InstantiationAwareBeanPostProcessor | postProcessBeforeInstantiation() | 返回代理对象代替Spring默认实例化(极少用,如创建动态代理替代原Bean)。 |
| 3. 实例化后/属性注入前 | InstantiationAwareBeanPostProcessor | postProcessAfterInstantiation() | 控制是否进行属性注入(返回false则跳过注入)。 |
| 4. 属性注入时 | InstantiationAwareBeanPostProcessor | postProcessProperties() | 自定义字段注入逻辑(如处理自定义@MyAutowired注解)。 |
| 5. 注入属性后 | BeanNameAware | setBeanName() | 获取当前Bean在容器中的ID。 |
| 5. (续) | BeanFactoryAware | setBeanFactory() | 获取BeanFactory,用于手动获取其他Bean。 |
| 5. (续) | ApplicationContextAware | setApplicationContext() | 获取ApplicationContext(环境、发布事件等)。 |
| 6. 初始化前置处理 | BeanPostProcessor | postProcessBeforeInitialization() | 对Bean进行包装(如标记字段、校验),注意:此时代理尚未生成。 |
| 7. 初始化时 | @PostConstruct(注解) | - | 执行自定义初始化逻辑(最常用)。 |
| 7. (续) | InitializingBean(接口) | afterPropertiesSet() | 编程式初始化(接口方式)。 |
| 7. (续) | @Bean(initMethod="xxx") | - | 指定初始化方法(XML或配置类方式)。 |
| 8. 初始化后置处理 | BeanPostProcessor | postProcessAfterInitialization() | AOP创建代理对象的标准时机,返回的对象最终存入容器。 |
| 9. 销毁时 | @PreDestroy(注解) | - | 释放资源(最常用)。 |
| 9. (续) | DisposableBean(接口) | destroy() | 编程式销毁(接口方式)。 |
| 9. (续) | @Bean(destroyMethod="xxx") | - | 指定销毁方法。 |
| 正常情况是实例化之后生成代理对象也就是在8. 初始化后置处理,当有循环依赖的情况会在2. 实例化前生成代理对象。 |
三级缓存存放的是什么
- 一级缓存:成品对象
- 二级缓存:半成品对象
- 三级缓存:lamda表达式,放入的函数是:
getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean)参数bean是方法doCreateBean方法通过反射实例化的对象。
一级缓存能解决缓存依赖吗
结论:理论上可以,但是实际上没人这样做,使用2个缓存的目的是为了区分成品对象和半成品对象的。
一级缓存失败案例:假设线程Q1实例化后属性注入前,将实例化后的对象A放入一级缓存后,然后线程A被阻塞了,此时线程Q2也要获取A,从缓存中拿到了直接返回,但是这个返回的对象并没有完成属性赋值,是一个不完整的对象。
二级缓存能解决缓存依赖吗
- 结论:可以解决,但是有个前提,循环依赖的对象就是普通Bean对象,一旦这个Bean对象需要AOP代理,就会报错。
为什么使用三级缓存能解决对象需要AOP的代理的问题
1,一个Map中,能包含2个同名的对象(一个原始对象一个代理对象)吗,显然不行
2,创建对象的时候有没有可能需要生成代理对象。很有可以
3,如果需要创建代理对象,那么程序如何用代理对象替换原始对象?因为没有循环依赖的Bean创建代理对象是初始化的时候创建的,如果你想要替换代理对象替换原始对象,就需要在属性赋值之前判断需不需创建代理对象。
4,为什么非要使用Lambda完成呢?
延迟执行:
- 没有循环依赖:需要AOP时,因为没有循环Bean依赖,三级缓存中的Lambda永远不会在实例化的时候执行,代理对象会在初始化后创建。
- 有循环依赖:需要AOP时,因为没有循环Bean依赖,当其他Bean(如B)在填充属性时通过
getBean触发了对A的依赖,Spring才会真正执行这个Lambda,生成代理对象。
三级缓存
循环依赖
Spring创建Bean时流程是 实例化 -> 填充属性 -> 初始化
实例化:调用构造方法(有参或无参构造)创建对象。
属性填充:依赖注入。
初始化:这里的初始化时Spring创建Bean的初始化,一般调用
@PostConstruct标注的方法,@Bean(initMethod="xxx")指定的方法,InitializingBean.afterPropertiesSet()实现该接口的方法,在初始化阶段,你可以放心地使用所有依赖的属性,因为 Spring 已经保证了它们都注入了。构造方法注入:不能解决循环依赖。1. Spring创建A,调用A的构造方法,发现需要B。2. Spring去创建B,调用B的构造方法,发现需要A。3. 此时A还没创建完成(卡在构造方法里)
懒加载(@Lazy):能解决
@Lazy的原理是代理。它不会注入真正的目标对象,而是注入一个代理对象.。Spring不急着去创建真正的B,而是生成一个B的代理对象(占位符)注入给A。当A后续真正调用B的方法时,代理对象才会去获取真正的B实例执行逻辑。
Spring中用到哪些设计模式
- 简单工厂-BeanFactory
- 工厂模式-FactoryBean
- 单例模式-bean是单例的
- 代理模式-AOP代理
- 观察者模式-spring的事件监听
- 适配器模式-springMvc的处理器适配器
- 装饰器模式-BeanWapper
Spring事务的传播行为有哪些
| 事务传播行为类型 | 外部不存在事务 | 外部存在事务 |
|---|---|---|
| REQUIRED(默认) | 开启新的事务 | 融合到外部事务,即使用外部事务 |
| REQUIRES_NEW | 开启新的事务 | 不使用外部事务,自己创建新的事务 |
| SUPPORTS | 不开启新的事务 | 融合到外部事务,即使用外部事务 |
| NOT_SUPPORTED | 不开启新的事务 | 不使用外部事务,没有事务 |
| NEVER | 不开启新的事务 | 抛出异常 |
| MANDATORY | 抛出异常 | 融合到外部事务,即使用外部事务 |
| NESTED | 开启新的事务 | 融合到外部事务,设置savepoint机制,外层影响内存,内存不影响外层。 |
spring的常见钩子
方法