上文中讲到authUserServiceImpl的代理类通过ObjenesisCglibAopProxy的方式创建出来,这篇文章继续分析,代理类的目标方法在调用之前,事务的创建过程,同样使用前文中提到的测试例子。
public class AuthUserServiceImplTest {
private static Logger logger = Logger.getLogger(AuthUserServiceImplTest.class);
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
IAuthUserService authUserServiceImpl = ctx.getBean(AuthUserServiceImpl.class);
int ret = authUserServiceImpl.delete("user002");
}
}
从下面的截图中可以看得出来,authUserServiceImpl这个变量实际引用的是内存中的“AuthUserServiceImpl$EnhancerBySpringCGLIB$ea1acdac@3108”对象,这是cglib通过字节码增加的方式,创建出来的代理对象,只存在于内存中。通过断点调试可以看出来,代理类中存在一系列的拦截器,
执行authUserServiceImpl.delete("user002")方法,通过调试执行下一步之后,就会进入到CglibAopProxy$DynamicAdvisedInterceptor这个拦截器的intercept()方法,其他的拦截器打了断点,貌似都没有执行,至于什么时候执行,不是本文关注的重点,忽略。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
try {
target = this.getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
}
return retVal;
}
这个intercept方法中得到了一个chain列表,列表中存放的就是两个拦截器,一个是ExposeInvocationInterceptor,另外一个就是TransactionInterceptor,
![]() | ![]() |
这两个拦截器是从哪儿来的呢?
从代码可以看得出来是和这个advised变量有关,这个变量引用的就是一个ProxyFactory,从上文记录,创建代理之前,首先创建了一个ProxyFactory,这段代码在AbstractAutoProxyCreator.createProxy()方法中。下面省略了部分代码。
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
Advisor[] var7 = advisors;
int var8 = advisors.length;
for(int var9 = 0; var9 < var8; ++var9) {
Advisor advisor = var7[var9];
proxyFactory.addAdvisor(advisor);
}
return proxyFactory.getProxy(this.getProxyClassLoader());
}
从这一行proxyFactory.addAdvisor(advisor)就可以看出,在创建代理工厂的时候,直接放了两个advisor配置器,一个是ExposeInvocationInterceptor的成员变量public static final Advisor ADVISOR,这是一个默认的配置器,不是我们分析的重点,忽略,以下省略部分代码,
public class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {
public static final Advisor ADVISOR;
static {
ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
public String toString() {
return ExposeInvocationInterceptor.class.getName() + ".ADVISOR";
}
};
invocation = new NamedThreadLocal("Current AOP method invocation");
}
}
| ![]() |
另外一个是DefaultBeanFactoryPointcutAdvisor,<aop:advisor>标签对应的classbean对象是DefaultBeanFactoryPointcutAdvisor,从上面的类图可以看出,他们都是Advisor的实现类,这两个advisor又是从哪儿来的呢?
框架在初始化目标bean的时候,会调用处理器AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()方法,这个过程中,处理器会从beanFactory工厂中取出所有的Advisor的实现类,并将其存储在上面我们看到的Object[] specificInterceptors变量中。
这两个Advisor的内部会有一个Advice的成员变量,DefaultPointcutAdvisor的advice是ExposeInvocationInterceptor,从上面的类图中可以看出ExposeInvocationInterceptor既是一个MethodInterceptor拦截器,也是一个advice,DefaultBeanFactoryPointcutAdvisor的advice是TransactionInterceptor,从上面的类图中可以看出TransactionInterceptor既是一个MethodInterceptor拦截器,也是一个advice。
回到上面的问题,List<Object> chain中这两个拦截器是从哪儿来的呢?就是从这两个Advisor中获取出来的。
CglibAopProxy$DynamicAdvisedInterceptor这个拦截器的intercept()方法中拿到这两个拦截器之后,就会调用CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed()方法,看看proceed()方法具体内容:
public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return this.invokeJoinpoint();
} else {
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
} else {
return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
}
}
}
这个变量中interceptorsAndDynamicMethodMatchers存放的就是上面提到的两个拦截器,这个方法的作用就是顺序调用两个拦截器的invoke()方法。代码中并没有使用for循环来遍历interceptorsAndDynamicMethodMatchers这个集合,那是怎么做到顺序调用所有的拦截器的呢?
因为在调用拦截器的invoke(this)方法的时候,传入了this,也就是传入了CglibAopProxy$CglibMethodInvocation的实例,这样其他的拦截器中就会有获取到这个CglibMethodInvocation的引用,比如看看ExposeInvocationInterceptor这个拦截器中的invoke方法:
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = (MethodInvocation)invocation.get();
invocation.set(mi);
Object var3;
try {
var3 = mi.proceed();
} finally {
invocation.set(oldInvocation);
}
return var3;
}
从mi.proceed();这行就可以看得出来,使用mi这个变量,又调用回CglibMethodInvocation的proceed()方法。回到proceed()方法之后,this.currentInterceptorIndex已经被++,这样就可以取到列表中下一个拦截器,进而执行下一个拦截器的invoke()方法。
ExposeInvocationInterceptor拦截器做了什么事情不是关注的重点,忽略,我们重点分析TransactionInterceptor这个拦截器中的内容。
TransactionInterceptor拦截器的invoke()方法调用了invokeWithinTransaction()方法,同时创建了一个匿名类,这个匿名类的方法中又执行了invocation.proceed(),执行完invokeWithinTransaction()方法之后,程序就会回到CglibAopProxy.CglibMethodInvocation.proceed()方法。
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
在TransactionInterceptor拦截器中invokeWithinTransaction()方法中,定义了整个事物控制的流程。
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
//开启事物
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
//执行目标方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//执行目标方法异常回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}finally {
cleanupTransactionInfo(txInfo);
}
//提交事物
commitTransactionAfterReturning(txInfo);
return retVal;
}
}
事物控制的流程大致分为3 步,第一步开启事物,第二步执行目标方法,第三部,提交事务,如果出现异常情况,进入异常分支处理异常。首先看看事物的创建过程。
开启事物
开启事物的过程中,会创建几个关键的和事物相关的对象,DataSourceTransactionManager、DataSourceTransactionObject、DefaultTransactionStatus、TransactionInfo、RuleBasedTransactionAttribute等
创建事物属性RuleBasedTransactionAttribute
事物拦截器TransactionInterceptor有一个私有变量TransactionAttributeSource transactionAttributeSource,它的实现类是NameMatchTransactionAttributeSource,它是<tx:attributes>标签对应的classbean对象。根据bean.xml中的配置:
<tx:attributes>
<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
<tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
<tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
<tx:method name="remove*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
<tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
<tx:method name="select*" propagation="SUPPORTS"/>
<tx:method name="query*" propagation="SUPPORTS"/>
</tx:attributes>
spring会将tx:method标签解析成为一个RuleBasedTransactionAttribute对象,并将其存储在transactionAttributeSource中的一个私有的成员变量,private Map<String, TransactionAttribute> nameMap = new HashMap<String, TransactionAttribute>()。
![]() |
按照当前的例子,我们调用的目标方法是authUserServiceImpl.delete("user002"),所以根据方法的名字delete,就可以从nameMap中获取到一个TransactionAttribute,这个TransactionAttribute中记录了事物的传播特性、事物的隔离级别、事物的异常回滚等信息。
创建事物DataSourceTransactionObject
事物拦截器中有一个私有成员变量,private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache,该变量中记录系统配置的事物管理器。目前系统配置的是org.springframework.jdbc.datasource.DataSourceTransactionManager,事物的创建主要交给事物管理器DataSourceTransactionManager来完成,
protected Object doGetTransaction() {
DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
通过new关键字来创建事物对象DataSourceTransactionObject,这个对象是事务管理器的一个内部类。
创建事物状态DefaultTransactionStatus
接着创建事物状态DefaultTransactionStatus,通过new关键创建事物状态对象,new DefaultTransactionStatus( transaction, newTransaction,actualNewSynchronization,definition.isReadOnly(), debug, suspendedResources);
事物状态创建完成之后,就从数据源DruidDataSource对象中的连接池中获取一个连接DruidConnectionHolder,连接池是一个数组,private volatile DruidConnectionHolder[] connections,这个connections数组中的连接是什么时候创建的呢?看看我们的bean.xml当中数据源的配置:
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
destroy-method="close" parent="dbCommProperty">
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true"/>
<property name="username" value="1111111"/>
<property name="password" value="1111111"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
数据源DruidDataSource在实例化之后,spring会调用bean配置的初始化方法,此处配置的init-method="init",表达的意思就是调用数据源DruidDataSource的init()方法,完成数据源的初始化。DruidDataSource在获取到DruidConnectionHolder连接之后,又将其封装成为DruidPooledConnection对象,之后在返回给事务管理器。
事务管理器在拿到连接之后,将连接的自动提交设置为false,con.setAutoCommit(false),关闭自动提交。
接着调用事物同步管理器TransactionSynchronizationManager,将当前的连接绑定在当前线程,通过ThreadLocal来实现,事物同步管理器内部定义了一个私有的成员变量,private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<Map<Object, Object>>("Transactional resources"),用来将当前的数据源连接和当前线程绑定。Map<Object, Object>中的key就是DruidDataSource对象,value就是当前获取到的数据源连接ConnectionHolder,
事物同步管理器TransactionSynchronizationManager中还定义了很多这样的ThreadLocal,用来缓存当前线程、当前事物所处的状态信息:
public abstract class TransactionSynchronizationManager {
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<Map<Object, Object>>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<String>("Current transaction name");
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<Boolean>("Current transaction read-only status");
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<Integer>("Current transaction isolation level");
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<Boolean>("Actual transaction active");
}
创建事物信息TransactionInfo
接下来就是事物拦截器TransactionInterceptor,创建事物信息new TransactionInfo(tm, txAttr, joinpointIdentification),事物信息TransactionInfo内部有一个成员变量TransactionInfo oldTransactionInfo,此变量保存着上一个事物信息的引用。
以上几个类的类图如下:
调用目标方法
和事物相关的类创建和组装完成之后,就进入到调用目标方法的阶段。但是调用目标方法的地方并不在事物拦截器TransactionInterceptor中,而是在CglibAopProxy$CglibMethodInvocation类中的proceed()方法,事物拦截器中invokeWithinTransaction()方法只是定义了事物执行的流程,在回顾一下这段代码:
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
//获取事物属性
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
//获取事物管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
//创建事物信息
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
//调用目标方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
调用invocation.proceedWithInvocation()的目的就是调用目标的方法,但是这是怎么回到CglibAopProxy$CglibMethodInvocation类的proceed()的方法的呢?
事物拦截器TransactionInterceptor的invoke方法中,直接调用了invokeWithinTransaction()方法,invokeWithinTransaction()方法只是定义事物执行的流程。但是传入的参数中有一个匿名类new InvocationCallback(),在这个匿名类的proceedWithInvocation()方法中调用了invocation.proceed(),这个invocation是什么对象呢?它其实引用的就是CglibAopProxy$CglibMethodInvocation对象实例。
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
通过以上的代码设计,就自然回到了CglibAopProxy$CglibMethodInvocation的proceed()方法中,以下代码有忽略。
public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return this.invokeJoinpoint();
}
}
回到proceed()方法之后,就执行this.invokeJoinpoint(),因为interceptorsAndDynamicMethodMatchers集合中所有的拦截器已经执行完成,invokeJoinpoint()方法中的内容就是去调用我们的目标方法。
我们在来梳理一下这个调用过程:
可以看出CglibAopProxy.CglibMethodInvocation.proceed()这个方法,被调用了多次,除了第一次调用,后面的几次调用都是在拦截器中通过回调的方式执行的,这样的调用方法增加了的类耦合性,为什么这样设计呢?为什么不直接通过for循环调用拦截器呢,我想这是因为这种回调的方式,形成了一个调用链,如果我们的目标方法抛出异常了之后,在这个链条上的拦截器都能收到异常信息,拦截器中可以根据异常信息作出自己的处理逻辑,事物拦截器如果要控制事物的流程,就必须知道目标方法执行正常与否,如果目标方法执行正常,事物正常提交,如果目标方式执行异常,事物回滚。
提交事物
目标方法AuthUserServiceImpl.delete()执行完成之后,根据调用的链,程序又会回到TransactionInterceptor.invoke()方法,在这个方法中执行事物的提交逻辑。大致做了以下几件事情:
- 调用connection的commit()方法,执行提交操作
- 释放当前连接connection到连接池中
- 设置事物状态DefaultTransactionStatus的的成员变量boolean completed = true
- 清理事物同步管理器TransactionSynchronizationManager中的缓存状态,解除当前线程绑定的连接connection
- 恢复当前连接connection的默认设置,比如自动提交状态设置为true,boolean autoCommit = true
事物创建过程的时序图如下,不代表实际的执行过程,意在说明问题: