spring声明式事务如何织入事务逻辑

问题

  1. @Transactional 注解标注的申明式事务是用 AOP 实现的,那么事务逻辑是怎么织入的呢?
  2. 织入的事务逻辑,是怎么处理连接的?底层的 dao 实现也需要连接,应该是用 ThreadLocal 做的,那么具体是怎么实现的?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
// ...
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
// ...
}
Read more

spring一例事务执行问题

问题

事务执行的代码:

1
2
3
4
5
6
@Transactional
@Override
public CheckResult check(TradeCheckDO tradeCheckDO) {
// 一次查询,查询库A A1表
// 一次查询,查询库B B1表
}

这里的问题是第二次查询,在执行 select … B1 时,没有在 B 库上执行,而是在 A 库上查 B1 表,就报错了。这个原因应该是数据源(DataSource)用的是动态数据源,导致没有重新获取连接。

Read more

Spring IOC循环引用源码分析

Spring bean 有两种注入方式,构造器注入和 set 注入。后者经过测试循环引用是不会报异常的,前者会报异常。

set 的方式

set 的方式默认是支持循环引用的,如果想设置成不支持,可以将 BeanFactory 实现类的 allowCircularReferences 设置成 falses。ApplicationContext 和 BeanFactory 基础的实现类都有这个参数可以设置。

spring 初始化 bean 的时候,是先构造一个空的对象,然后再根据需要去初始化属性指向的 bean。比如 B1 -> B2 为 B1 后属性引用 B2,同时 B2 -> B1。当去初始化 B2 的时候,在设置自己指向 B1 的属性时,是直接用 B1 还未完全构造完成的对象。

比如 B2 在需要去设置对 B1 的引用时,会调用 BeanFactory 的 getBean 方法。这个 getBean 方法的逻辑在最前端会去查一个缓存,这个缓存里放了先前已经开始初始化,但是还没有把属性设置完全的 bean 引用缓存。如果缓存非空,就直接用这个引用返回。如果缓存为空,就去调一个 ObjectFactory 对象的 getObject 方法作为 bean 引用返回。这个 ObjectFactory 是先前 B1 初始化时,被 new 出来以后,加进一个 ObjectFactory 容器的:

1
2
3
4
5
6
// AbstractAutowireCapableBeanFactory.doCreateBean
addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
Read more