Spring 5.2.0 执行流程 密码 j883
AOP 执行流程 密码 INcj
Spring 流程概览 密码 Vz2r
BeanFactory : 基础的 IOC 容器,管理 bean 对象以及对象之间的依赖绑定关系的工厂,最底层的接口
ApplicationContext : BeanFactory 的实现类,不仅拥有 BeanFactory 所有的功能,还提供了其他高级特性:如:时间发布、国际化信息支持等,默认在容器启动时,所有由 spring 管理的对象都会初始化并且绑定完成
BeanDefinition : bean 的定义信息,spring 根据定义信息实例化(反射生成对象,开辟堆空间)与初始化对象
BeanDefinitionRegistry : 对 BeanDefinition 进行增删改查的接口
BeanDefinitionReader : 用于配置文件的的加载,构造器是传入 BeanDefinitionRegistry,通过 loadBeanDefinitions 方法把定义好的 bean 信息 转换为 beanDefinition 注册到注册器里
BeanDefinitionParserDelegate : 判断标签是否是默认标签、解析自定义标签、装饰 BeanDefinition等,也就是 BeanDefinition 解析的工作都是由这个类完成的。包含 XmlReaderContext
XmlReaderContext : 后面还会通过它来获取 BeanDefinitionRegistry ,如果除了import、alias、bean、beans默认的标签,别的自定义标签解析需要使用该类的 NamespaceHandlerResolver 对象根据标签获取 NamespaceHandler,然后通过 NamespaceHandler 解析并注册 BeanDefinition
BeanFactoryPostProcessor : 处于容器启动阶段,能获取到 ConfigurableListableBeanFactory ,可以用来在容器实例化之前,对注册在容器中的 beanDefinition 所保存的信息做相应修改,如果需要保证 各个 BeanFactoryPostProcessor 按照顺序执行,还需要实现 Order 接口。
Aware : 翻译是意识到的,例如 BeanNameAware 就是能获取到BeanName,可以使用 Aware 的接口做很多扩展操作BeanNameAware : 重写 setBeanName 方法,可以获取到该 bean 对应的 beanName
BeanFactoryAware : 可以获取该 bean 所处的 beanFactory , 并且使用 beanFactory 来做扩展操作
BeanPostProcessor : 重写 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法:
- postProcessBeforeInitialization 的参数有:bean 对应的 beanName 和 完成实例化与赋值后的对象;
- postProcessAfterInitialization 的参数有:执行完 init-method 方法后的对象与 bean 对应的 beanName。
ApplicationContextAwareProcessor : BeanPostProcessor 的实现类,在 doCreateBean 时,initializeBean 方法里的 invokeAwareMethods 只会执行BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 三个 Aware 的方法,但是 Aware 还有很多实现类,也需要在特定时间执行,所以有了 ApplicationContextAwareProcessor ,但是它是在 invokeAwareMethods 之后的 applyBeanPostProcessorsBeforeInitialization 方法里执行的,即是在后置处理器的时候才会执行EnvironmentAware、ResourceLoaderAware 等对应 Aware 要执行的逻辑
ConfigurationClassPostProcessor : 解析各种配置类注解的 BeanDefinitionRegistryPostProcessor,在解析context:component-scan 时把相关的 BeanDefinition 注册进 registry 里的;
sptingBoot 启动类的注解里面有 Import 注解,就是通过 ConfigutationClassPostProcessor 解析 @Import 时进行的自动装配
lookup-method 解决单例引用原型的问题,指定方法名,与要引用的 bean ,然后 bean 调用这个方法的时候,会去创建被引用的 bean,如果这个 bean 是原型的,就会每次都生成新对象的来执行方法,而引用 lookup-method 的 bean ,引用对象是在 instantiate 方法里判断,使用 CGLIB 生成的一个代理对象,而调用被指定的方法时,获取到的 bean 是通过 LookupOverrideMethodInterceptor 的 intercept 获取的。
Spring 事务
@Transactional
是使用 AOP 的方式生成代理,对加上 @Transactional 注解的方法进行增强
@Transactional 与锁一起使用,可能出现问题
private Lock lock = new ReentrantLock(true);
@Transactional(rollbackFor = Exception.class)
public CommonResult<String> func(long seckillId, long userId) {
// 1、加锁
lock.lock();
// 2、查询库存、减库存
// 3、加锁
lock.unlock();
return new CommonResult<>(CommonResultEmnu.OK);
}
事务的开启的代码肯定是在原方法之前执行的,但是这里只是事务就绪而已,也就是说 begin / start transaction 语句并不是一个事务真正开始的地方,而第一个操作 InnoDb 表的语句才是真正的事务启动时机。
事务的回滚和提交都是在原方法执行完之后才进行的,所以会出现锁已经释放了,但是事务还没提交,别的事务拿到锁之后再查询库存还是原来的数据,可能造成超卖。
解决方法:
- 把原方法拆分为加锁解锁方法和查询库存、减库存两个方法,都加上 @Transactional,并且查询库存减库存的事务传播机制改为 @Transactional(propagation=Propagation.REQUIRES_NEW)
- 使用编程式事务
- mp.weixin.qq.com/s/_wnj-8SKo…