spring 事务

spring的事务是从TransactionProxyFactoryBean开始的TransactionProxyFactoryBean也是一个FactoryBean

源码如下:
public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean
implements BeanFactoryAware
{

public TransactionProxyFactoryBean()
{
}

public void setTransactionManager(PlatformTransactionManager transactionManager)
{
transactionInterceptor.setTransactionManager(transactionManager);
}

public void setTransactionAttributes(Properties transactionAttributes)
{
transactionInterceptor.setTransactionAttributes(transactionAttributes);
}

public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource)
{
transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
}

public void setPointcut(Pointcut pointcut)
{
this.pointcut = pointcut;
}

public void setBeanFactory(BeanFactory beanFactory)
{
transactionInterceptor.setBeanFactory(beanFactory);
}

protected Object createMainInterceptor()
{
transactionInterceptor.afterPropertiesSet();
if(pointcut != null)
//设置默认的通知器
return new DefaultPointcutAdvisor(pointcut, transactionInterceptor);
else
//使用事务属性通知器
return new TransactionAttributeSourceAdvisor(transactionInterceptor);
}

private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
private Pointcut pointcut;
}

那么transactionInterceptor这个拦截器是在什么时候启动的。
我们在AbstractSingletonProxyFactoryBean中可以看到产生事务代理对象是在该类中的afterPropertiesSet方法中,其源码如下:
public void afterPropertiesSet()
{
if(target == null)
throw new IllegalArgumentException("Property 'target' is required");
if(target instanceof String)
throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
if(proxyClassLoader == null)
proxyClassLoader = ClassUtils.getDefaultClassLoader();
ProxyFactory proxyFactory = new ProxyFactory();
if(preInterceptors != null)
{
Object aobj[];
int k = (aobj = preInterceptors).length;
for(int i = 0; i < k; i++)
{
Object interceptor = aobj[i];
proxyFactory.addAdvisor(advisorAdapterRegistry.wrap(interceptor));
}

}
//配置通知器
proxyFactory.addAdvisor(advisorAdapterRegistry.wrap(createMainInterceptor()));
if(postInterceptors != null)
{
Object aobj1[];
int l = (aobj1 = postInterceptors).length;
for(int j = 0; j < l; j++)
{
Object interceptor = aobj1[j];
proxyFactory.addAdvisor(advisorAdapterRegistry.wrap(interceptor));
}

}
proxyFactory.copyFrom(this);

if(proxyInterfaces != nullTargetSource targetSource = createTargetSource(target);
//设置目标接口
proxyFactory.setTargetSource(targetSource);)
//设置代理接口
proxyFactory.setInterfaces(proxyInterfaces);
else
if(!isProxyTargetClass())
proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), proxyClassLoader));
proxy = proxyFactory.getProxy(proxyClassLoader);
}

Spring事务处理完成AOP配置的地方,这个afterPropertiesSet方法功能实现如下代码


下面我们分析下事务属性的读入
从TransactionProxyFactoryBean中我们可以看到TransactionAttributeSourceAdvisor,我们以这个类为入口从而了解事务属性是如何注入的
TransactionAttributeSourceAdvisor 是一个通知器包含了切面和通知

public TransactionAttributeSourceAdvisor()
{
pointcut = new TransactionAttributeSourcePointcut() {

protected TransactionAttributeSource getTransactionAttributeSource()
{
return transactionInterceptor == null ? null : transactionInterceptor.getTransactionAttributeSource();
}

final TransactionAttributeSourceAdvisor this$0;


{
this$0 = TransactionAttributeSourceAdvisor.this;
super();
}
}
;
}

在声明式事务处理中,是通过对目标对象的方法调用拦截实现,这个拦截通过AOP发挥过作用。对于拦截器启动,首先需要对方法调用是否需要拦截器进行判断,而判断的依据是那些在TrasactionProxyFactoryBean中为目标对象设置的事务属性。也就是说需要判断当前的目标方法调用是不是一个配置好的,需要进行事务处理方法调用。具体说,这个匹配判断在TransactionAtrributeSourcePoincut中完成,它的实现如代码如下:
public boolean matches(Method method, Class targetClass)
{
TransactionAttributeSource tas = getTransactionAttributeSource();
return tas == null || tas.getTransactionAttribute(method, targetClass) != null;
}

在pointcut的matches判断过程中,会用到transactionAttributeSource对象,这个对象是在对TranasactionInterceptor进行依赖注入时就配置好了的。它的设置是在基类TransactionAspectSupport完成的,配置了一个NameMatchTransactionAttributeSource代码如下:

public void setTransactionAttributes(Properties transactionAttributes)
{
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
tas.setProperties(transactionAttributes);
transactionAttributeSource = tas;
}


在应用调用目标方法的时候,因为这个目标方法已经被TrasactionProxyFactoryBean代理,所以TrasactionProxyFactoryBean需要判断这个方法是否是事务方法。这个判断的实现,是通过NameMatchTransactionAttributeSource中,能否为这个调用方法事务属性来完成的.具体的实现过程是这样的: 首先,使用调用方法作为索引的namemap中去查找相应的事务处理性值,如果能够找到,那么就说明调用方法和事务方法直接对应,如果找不到,那么就会遍历整个nameMap,对保存在其中的每一个方法名,使用PatternMatchUtils进行命名模式上的匹配。这里使用PatternMatchUtils进行匹配,是因为在设置事务方法的时候,就像我们常见的那样,可以不需要为事务设置一个完整的方法名,而是可以通过设置方法名的命名模式来完成,比如可以通过像对通配符*的使用。

我们看下NameMatchTransactionAttributeSource中的setProperties方法
public void setProperties(Properties transactionAttributes)
{
TransactionAttributeEditor tae = new TransactionAttributeEditor();
String methodName;
TransactionAttribute attr;
for(Enumeration propNames = transactionAttributes.propertyNames(); propNames.hasMoreElements(); addTransactionalMethod(methodName, attr))
{
methodName = (String)propNames.nextElement();
String value = transactionAttributes.getProperty(methodName);
tae.setAsText(value);
attr = (TransactionAttribute)tae.getValue();
}

}
public TransactionAttribute getTransactionAttribute(Method method, Class targetClass)
{
//判断当前目标调用的方法与配置事务方法,是否匹配
String methodName = method.getName();
TransactionAttribute attr = (TransactionAttribute)nameMap.get(methodName);
if(attr == null)
{
String bestNameMatch = null;
for(Iterator iterator = nameMap.keySet().iterator(); iterator.hasNext();)
{
String mappedName = (String)iterator.next();
if(isMatch(methodName, mappedName) && (bestNameMatch == null || bestNameMatch.length() <= mappedName.length()))
{
attr = (TransactionAttribute)nameMap.get(mappedName);
bestNameMatch = mappedName;
}
}

}
return attr;
}


通过以上过程,可以得到与目标对象调用方法相关TransactionAttribute对象,在这个对象中,封装了事务处理的配置。


事务处理拦截器的实现

在完成以上准备工作后,经过TransactionProxyFactoryBean的AOP包装,此时如果对目标对象进行方法调用,其调用起作用对象实际是一个proxy代理对象,对目标对象方法的调用,不会直接作用在TransactionProxyFactoryBean设置的目标对象上,而会被设置的事务处理拦截器,而对于TransactionProxyFactoryBean的AOP实现中,获取Proxy对象的过程,这个过程并不复杂,TransactionProxyFactoryBean作为一个Factorybean,对这个bean对象的引用,是通过调用TransactionProxyFactoryBean的getObject方法来得到的,我们对这个方法已经很熟悉了

public Object getObject()
{
if(proxy == null)
throw new FactoryBeanNotInitializedException();
else
return proxy;
}

关于如何对AOP代理作用可以看下spring中AOP源码的分析,我们可以注意下TransactionInteceptor中的invoke方法其源码如下:

public Object invoke(final MethodInvocation invocation) throws Throwable {
//这里得到目标对象
Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);

//这里同样的通过判断是否能够得到TransactionAttribute来决定是否对当前方法进行事务处理,有可能该属性已经被缓存,
//具体可以参考上面对getTransactionAttribute的分析,同样是通过TransactionAttributeSource
final TransactionAttribute txAttr =
getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
final String joinpointIdentification = methodIdentification(invocation.getMethod());

//这里判断我们使用了什么TransactionManager
if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
// 这里创建事务,同时把创建事务过程中得到的信息放到TransactionInfo中去
TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
Object retVal = null;
try {
retVal = invocation.proceed();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}

else {
// 使用的是Spring定义的PlatformTransactionManager同时实现了回调接口,我们通过其回调函数完成事务处理,就像我们使用编程式事务处理一样。
try {
Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,
new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
//同样的需要一个TransactonInfo
TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
try {
return invocation.proceed();
}
});
}
}


在invoke方法中我们可以看到,首先先获得调用方法的事务处理配置,在得到事务处理配置以后,会取得PlatformTranasctionManager由这个事务处理器来实现事务的创建、提交、回滚操作。PlatformTranasctionManager是在IOC容器中配置的。我们比较熟悉有DataSourceTransactionManager和HiberanteTransactionManager等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值