一、Spring Bean的生命周期
- 创建、使用、销毁
- 再细分:实例化、初始化、注册Destruction回调、Bean的使用、Bean的销毁
- 再具体
- 实例化Bean
- 设置属性值
- 检查Aware
- 调用前置处理方法BeanPostProcessor
- 调用initializingBean的afterPropertiesSet方法
- 调用自定义init-method方法
- 调用后置处理方法BeanPostProcessor
- 注册Destruction回调
- Bean准备就绪
- 调用DisposableBean的destory方法
- 调用自定义的destory-method
二、@PostConstruct、init-method、afterPropertiesSet执行顺序
- 都是在Bean初始化阶段执行特定方法的
- 顺序:构造函数 > @PostConstruct > afterPropertiesSet > init-method
- @PostConstruct
- 表示这个方法在Bean初始化阶段被调用
- init-method
- 告诉Spring在Bean初始化完成后调用指定的初始化方法(xml配置文件里)
- 不用xml的话,可以@Bean(initMethod = 指定方法)
- afterPropertiesSet
- Bean如果实现了initializingBean接口,则在初始化阶段会调用afterPropertiesSet方法
三、Spring事务@transactional传播机制
- REQUIRED
- 如果不存在事务则开启一个事务,如果存在事务则加入之前事务(只有一个事务执行)
- REQUIRED_NEW
- 每次执行新开一个事务,如果当前存在事务,则把事务挂起
- SUPPORTS
- 有事务则加入事务,无事务则普通执行
- NOT_SUPPORTED
- 有事务则暂停该事务,无则普通执行
- MANDATORY
- 强制有事务,无事务则报异常
- NEVER
- 有事务则报异常
- NESTED
- 如果之前有事务,则创建嵌套事务,嵌套事务回滚不影响父事务,反之父事务影响嵌套事务(尽管嵌套事务在逻辑上是独立的,并且它的回滚不会影响父事务的其余部分,但如果父事务由于某种原因需要回滚(比如父事务中发生了运行时异常),那么嵌套事务也会受到影响,因为它实际上是父事务的一部分)
roolbackFor
- 用于指定哪些异常会触发事务回滚(不指定则默认runtimeException、Error)
具体场景
- Q:一个长的事务方法a,在读写分离的情况下,有读、写库的操作,在调用一个读库方法b,b应该用什么传播机制
- A:读如果是最后一步:not_supported(有事务则暂停该事务,无则普通执行)避免都报错导致数据回滚;如果是中间步骤:required(如果不存在事务则开启一个事务,如果存在事务则加入之前事务)因为异常失败需要回滚
- A、B、C三个操作,如果B失败了,就要让A回滚,因为C未执行,A回滚才能保证一致性
四、BeanFactory vs FactoryBean
- 两个都是接口,都在org.springframework.beans.factory包下
- BeanFactory
- Bean工厂,用来获取Bean(applicationContext.getBean)或负责管理Bean的创建和生命周期,是IOC容器的一部分
- FactoryBean
- 定义一个工厂Bean,用于创建很复杂的对象,比如需要某种特定的创建过程才能得到的对象(与JNDI资源连接或与代理对象的创建:Dubbo中的ReferenceBean)
- Spring配置文件中定义一个Bean时,如果这个Bean实现了FactoryBean接口,则Spring容器不直接返回这个Bean实例,而是返回getObject()一个对象
applicationContext
- 获取的bean必须是Spring托管的,即必须要与@Service、@Autowired一起用(自己new的bean不行)
五、如何开启事务
- 编程式事务
- 基于底层API:PlatformTransactionManager、TransactionDefinition、TransactionTemplate
- 我们手动在代码中管理事务transactionManager的开启getTransaction、提交commit、回滚rollback
- 或者TransactionTemplate:transactionTemplate.execute
- 声明式事务
- 注解或基于配置xml
- @Transactional
- 使用了AOP实现,在目标方法执行后进行拦截。在目标方法执行前加入或创建事务,在执行方法执行后,根据实际情况选择提交 or 回滚
- 对代码没有侵入性,专注于业务逻辑(AOP)
- 局限:最小粒度要作用在方法上(如果要给一部分代码块增加事务,就需要把这部分代码块单独独立出来作为一个方法)
- 失效:
- @Transactional用在非public方法上
- @Transactional注解属性propagation设置错误
- @Transactional注解属性rollbackFor设置错误
- 同一个类方法中调用,@Transactional失效
- 异常被捕获导致@Transactional失效
- 数据库引擎不支持事务
- @Transactional事务不要滥用。事务会影响数据库的QPS(Queries Per Second:每秒查询率),另外使用事务的地方需要考虑各方面的回滚方案:缓存回滚、搜索引擎回滚、消息补偿、统计修正