内容简介:在本篇文章中,将会介绍如何在spring中进行事务管理,之后对其内部原理进行分析。主要涉及我们可以在配置类上标记注解@EnableTransactionManagement,这样就可以设置spring应用开启事务管理。 之后我们可以在需要开启事务的方法上标注@Transactional,spring将利用AOP框架,生成代理类,为方法配置事务增强。下面看一个具体的例子从以上的demo,我们可以看出来。利用spring的事务管理框架,我们只需要三个步骤即可:
在本篇文章中,将会介绍如何在spring中进行事务管理,之后对其内部原理进行分析。主要涉及
- @EnableTransactionManagement注解为我们做了什么?
- 为什么标注了@Transactional注解的方法就可以具有事务的特性,保持了数据的ACID特性?spring到底是如何具有这样的偷梁换柱之术的?
- 中间涉猎到一些spring关于注解配置的解析逻辑分析,这一部分比较通用,并不是spring事务管理模块特有的功能。在往后分析spring其他模块代码的时候可以借鉴
如何在spring应用中使用事务
我们可以在配置类上标记注解@EnableTransactionManagement,这样就可以设置spring应用开启事务管理。 之后我们可以在需要开启事务的方法上标注@Transactional,spring将利用AOP框架,生成代理类,为方法配置事务增强。下面看一个具体的例子
demo
配置类
@Configuration
@EnableTransactionManagement // 我们这一节的重点研究对象
public class MybatisConfig {
// 各种其他配置,如数据源配置、mybatis的SqlSessionFactory等
}
复制代码
需要事务增强的接口类
// 接口类
public interface CountryService {
int createCountry(Country country);
}
// 实现,我们故意让其抛出异常
public class CountryServiceImpl implements CountryService {
// ... 注入countryMapper
@Override
@Transactional
public int createCountry(Country country) {
// 使用mybatis mapper来操作数据库
int result = countryMapper.insert(country);
int i = 1 / 0; // 抛出RuntimeException,事务回滚
return result;
}
}
复制代码
使用接口
public class ContextTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class);
CountryService countryService = context.getBean(CountryService.class);
Country country = new Country();
country.setCountryName("中国");
country.setCountryCode("CN");
// 由于我们在countryService中,抛出了异常。因此这里的数据将发生回滚,不会写入到数据库中
countryService.createCountry(country);
}
}
复制代码
demo说明了什么?
从以上的demo,我们可以看出来。利用spring的事务管理框架,我们只需要三个步骤即可:
- 通过注解@EnableTransactionManagement,开启spring的事务管理功能
- 在接口类的需要事务增强的方法上,标注@Transactional
- 在容器中使用增强后的代理类的事务方法,如countryService.createCountry(country)
spring是如何做到的呢?
区区三个步骤,就可以让我们解耦数据访问、事务管理这两个功能模块。神奇的背后,到底隐藏着什么原理呢?
从@EnableTransactionManagement开始探险
EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
复制代码
从注解的代码中,可以看出在其内部通过@Import注解导入了TransactionManagementConfigurationSelector类
TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* {@inheritDoc}
* @return {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and
* {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
复制代码
TransactionManagementConfigurationSelector实现了接口ImportSelector
spring加载配置流程
由于整个解析配置的流程过于复杂,代码量繁多。这里就不一一列出具体代码了。下面提供一个主流程的时序图,有兴趣的看官可以跟着流程图去浏览一下相关源码。
在spring解析配置的过程中,将调用方法AutoProxyRegistrar#registerBeanDefinitions,最终向容器中注册了自动代理生成器InfrastructureAdvisorAutoProxyCreator
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// 该方法内部将注册一个自动生成代理类(InfrastructureAdvisorAutoProxyCreator)
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound) {
String name = getClass().getSimpleName();
logger.warn(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
复制代码
而且,在解析配置的过程中,将处理Import进来的配置类ProxyTransactionManagementConfiguration。 其内部存在三个用@Bean注解标注的方法如下,将向容器注册其各自返回的bean。
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 注册一个切面
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}
//
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
// 切面逻辑(Advice)
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
复制代码
解析配置后的成果
- 注册了自动代理生成器InfrastructureAdvisorAutoProxyCreator
- 注册了ProxyTransactionManagementConfiguration,其内部会通过@Bean标注的方法,进而注册BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource、TransactionInterceptor
spring是如何为我们进行事务增强的
spring通过AOP框架在容器启动时,自动发现需要事务增强的类或方法(即标注了@Transactional的类或方法),为这些方法嵌入事务切面(即BeanFactoryTransactionAttributeSourceAdvisor)生成代理类,之后我们从容器获取到的对应的bean就是进行事务增强后的代理类。大致的步骤包括:
- InfrastructureAdvisorAutoProxyCreator作为BeanPostProcessor,在容器启动期间其postProcessAfterInitialization方法被调用,作为创建事务增强代理对象的入口
- 之后从beanfactory中获取所有Advisor实现类的实例,使用每一个获取到的Advisor中的Pointcut对当前正在创建的bean进行匹配,在这里Advisor为BeanFactoryTransactionAttributeSourceAdvisor、Pointcut为TransactionAttributeSourcePointcut
- 匹配过程中会调用TransactionAttributeSourcePointcut的matches(Method method, Class targetClass)方法来进行匹配判断,判断的工作需要借助AnnotationTransactionAttributeSource#getTransactionAttribute(Method method, Class targetClass)来解析注解@Transactional
- 如果匹配成功,则证明需要生成事务增强代理。会返回BeanFactoryTransactionAttributeSourceAdvisor实例,作为切面设置到ProxyFactory中,用于生成代理
- 通过ProxyFactory来生成事务增强代理
大致的流程图如下所示
事务增强代理生成过程的源码分析
InfrastructureAdvisorAutoProxyCreator(BeanPostProcessor)
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
// postProcessAfterInitialization接口在其父类中实现
}
复制代码
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 代理生成逻辑
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 在这个方法内部将调用TransactionAttributeSourcePointcut#match方法进行匹配,如果匹配成功那么会返回BeanFactoryTransactionAttributeSourceAdvisor实例
// 这个方法完成了以下几个工作
// 1. 从beanfactory中获取所有注册到beanfactory中的Advisor,将Advisor进行实例化
// 2. 调用Advisor中的Pointcut的matches方法,进行匹配。匹配成功则返回当前Advisor
// 3. 在事务管理的框架中,匹配细节由TransactionAttributeSourcePointcut#matches方法负责,其内部会调用AnnotationTransactionAttributeSource#getTransactionAttribute方法解析@Transactional注解
// 4. 对于局部事务来说,解析@Transactional的解析将委托给SpringTransactionAnnotationParser
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 在这个方法内部将使用ProxyFactory来生成代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
复制代码
BeanFactoryTransactionAttributeSourceAdvisor(Advisor)
这里先看一下BeanFactoryTransactionAttributeSourceAdvisor的类图,大概了解下这个类是在整个事务管理体系中是属于什么角色。
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
private TransactionAttributeSource transactionAttributeSource;
// 切面内的Pointcut,用于在生成代理的过程中进行匹配方法
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
/**
* Set the transaction attribute source which is used to find transaction
* attributes. This should usually be identical to the source reference
* set on the transaction interceptor itself.
* @see TransactionInterceptor#setTransactionAttributeSource
*/
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
/**
* Set the {@link ClassFilter} to use for this pointcut.
* Default is {@link ClassFilter#TRUE}.
*/
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
复制代码
可以看出,这个类间接实现了接口PointcutAdvisor,这是一个切面类(即组合了Pointcut、Advice)。其内部定义的Pointcut为抽象类TransactionAttributeSourcePointcut的匿名实现类。关于AOP的这些概念,可以参考:spring-AOP原理分析一和spring-AOP原理分析二,这里不再赘述。
TransactionAttributeSourcePointcut(Pointcut)
这个类间接实现了两个接口:Pointcut、MethodMatcher。在事务管理中作为AOP的pointcut、methodMatcher两个角色。用于匹配方法是否需要进行事务增强
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
// 通过AnnotationTransactionAttributeSource来获取
@Override
public boolean matches(Method method, Class<?> targetClass) {
if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
// 获取到的tas为AnnotationTransactionAttributeSource实例,
// 在ProxyTransactionManagementConfiguration中注册而来
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof TransactionAttributeSourcePointcut)) {
return false;
}
TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;
return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
}
@Override
public int hashCode() {
return TransactionAttributeSourcePointcut.class.hashCode();
}
@Override
public String toString() {
return getClass().getName() + ": " + getTransactionAttributeSource();
}
/**
* Obtain the underlying TransactionAttributeSource (may be {@code null}).
* To be implemented by subclasses.
*/
protected abstract TransactionAttributeSource getTransactionAttributeSource();
}
复制代码
AnnotationTransactionAttributeSource
在TransactionAttributeSourcePointcut#matches(Method method, Class targetClass)方法中,将调用AnnotationTransactionAttributeSource#getTransactionAttribute(Method method, Class targetClass)方法,用于获取TransactionAttribute,即配置到@Transactional的属性值。实际的获取动作代理给了父类AbstractFallbackTransactionAttributeSource
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
// ... 省略code
}
public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {
@Override
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
Object cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return (TransactionAttribute) cached;
}
}
else {
// We need to work it out.
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isDebugEnabled()) {
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
// 解析@Transaction注解的属性值
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
// Don't allow no-public methods as required.
// 1. 只有public方法可以切入事务管理
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// Ignore CGLIB subclasses - introspect the actual user class.
Class<?> userClass = ClassUtils.getUserClass(targetClass);
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// First try is the method in the target class.
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
@Override
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
if (ae.getAnnotations().length > 0) {
// TransactionAnnotationParser的实现类有Ejb3TransactionAnnotationParser、JtaTransactionAnnotationParser、SpringTransactionAnnotationParser
// 对于局部失误,我们使用SpringTransactionAnnotationParser来进行解析
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
if (attr != null) {
return attr;
}
}
}
return null;
}
}
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
}
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
Class<?>[] rbf = attributes.getClassArray("rollbackFor");
for (Class<?> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class<?> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
@Override
public boolean equals(Object other) {
return (this == other || other instanceof SpringTransactionAnnotationParser);
}
@Override
public int hashCode() {
return SpringTransactionAnnotationParser.class.hashCode();
}
}
复制代码
总结
以上我们从一个demo入手,了解了如何使用spring来管理事务;之后我们从配置的注解@EnableTransactionManagement切入到spring事务框架的内部原理。期间涉及了几个主要的类:
- AutoProxyRegistrar其主要职责是注册InfrastructureAdvisorAutoProxyCreator 1.1 InfrastructureAdvisorAutoProxyCreator,负责在容器启动期间利用配置信息生成事务增强的代理类对象
- ProxyTransactionManagementConfiguration其主要职责是注册AnnotationTransactionAttributeSource、TransactionInterceptor、BeanFactoryTransactionAttributeSourceAdvisor 2.1 AnnotationTransactionAttributeSource负责解析@Transactional注解 2.2 BeanFactoryTransactionAttributeSourceAdvisor作为切面,组合了Pointcut和Advice提供了事务管理的功能
- TransactionAttributeSourcePointcut作为Pointcut,负责匹配方法
- TransactionInterceptor作为Advice,事务管理的逻辑都在这个类中进行实现。
悬念
鉴于篇幅过长了,O(≧口≦)O。。。下一节我们再对事务管理的逻辑进行剖析,即对TransactionInterceptor进行分析
以上所述就是小编给大家介绍的《spring事务管理源码分析(一)配置和事务增强代理的生成流程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 在云中管理事务,第 1 部分: 事务基础和分布式事务
- 关系型数据库中的事务管理详解:并发控制与事务日志
- Spring 事务管理
- Hibernate事务管理
- Spring系列-事务管理
- Spring 系列:事务管理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web 2.0 Architectures
Duane Nickull、Dion Hinchcliffe、James Governor / O'Reilly / 2009 / USD 34.99
The "Web 2.0" phenomena has become more pervasive than ever before. It is impacting the very fabric of our society and presents opportunities for those with knowledge. The individuals who understand t......一起来看看 《Web 2.0 Architectures》 这本书的介绍吧!