摘要:使用注解方式简单模拟事务样例说明数据源采用采用持久化采用事务注解环境搭建依赖提供的模块链接驱动包配置类声明式事务配置类,其中一定要开启。
使用注解方式简单模拟事务样例 说明
数据源采用c3p0
采用JdbcTemplate持久化
采用Spring事务注解
环境搭建 POM依赖配置类c3p0 c3p0 0.9.1.2 org.springframework spring-jdbc 4.3.12.RELEASE mysql mysql-connector-java 5.1.44 runtime org.springframework spring-aspects 4.3.12.RELEASE
/** * description:声明式事务配置类,其中@EnableTransactionManagement * 一定要开启。 * @author 70KG */ @Configuration @ComponentScan("com.nmys.story.springCore.springaop.tx_sample") @EnableTransactionManagement // -- 开启基于注解的事务管理 public class TxConfig { // -- 配置数据源 @Bean public DataSource dataSource() throws Exception { ComboPooledDataSource pool = new ComboPooledDataSource(); pool.setUser("root"); pool.setPassword("root"); pool.setDriverClass("com.mysql.jdbc.Driver"); pool.setJdbcUrl("jdbc:mysql://localhost:3306/usthe?useSSL=false"); return pool; } // -- 加入模板 @Bean public JdbcTemplate jdbcTemplate() throws Exception { JdbcTemplate template = new JdbcTemplate(dataSource()); return template; } // -- 配置事务管理器,它才是用来提交回滚事务的主导者 @Bean public DataSourceTransactionManager txManager() throws Exception { DataSourceTransactionManager tx = new DataSourceTransactionManager(dataSource()); return tx; } }业务类
/** * description * @author 70KG */ @Service public class TxService { @Autowired private TxDao txDao; public void insertLog(){ txDao.insertSth(); } }
/** * description * @author 70KG */ @Repository public class TxDao { @Autowired private JdbcTemplate jdbcTemplate; // @Transactional仅表明它是一个事务方法,开启事务仅有注解是不够的,还需要配置事务管理器 @Transactional public void insertSth() { String sql = "INSERT into sys_log (username) VALUES(?);"; jdbcTemplate.update(sql, "lisi"); System.out.println("------>插入成功"); int i = 10/0; } }测试类
/** * description * @author 70KG */ public class Test01 { public static void main(String[] args) { AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(TxConfig.class); TxService bean = app.getBean(TxService.class); bean.insertLog(); } }测试结果
测试结果肯定是能正常运行的,下面试着跟一下源码。
源码分析当容器开始启动运行的时候就会找到@EnableTransactionManagement注解
进入注解,发现它使用@Import(TransactionManagementConfigurationSelector.class)向容器中注入了这个类
跟进TransactionManagementConfigurationSelector,发现它最终实现的是ImportSelector接口,这个接口可以向IOC容器中以Bean的全类名的方式注入Bean。
源码如下,AdviceMode在注解@EnableTransactionManagement默认就是PROXY,可见它向容器中注入了两个类,分别是AutoProxyRegistrar和ProxyTransactionManagementConfiguration。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelectorAutoProxyRegistrar{ @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; } } }
AutoProxyRegistrar翻译过来:自动代理注册器。进入AutoProxyRegistrar类,截取部分源码,如下:
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; SetannoTypes = 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) { // -- 前面的代码主要是获取注解类型,注解信息等等。 // -- 主要是这个地方,如果必要的话,就向容器中注册一个自动代理创建器。 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } ...........
进入registerAutoProxyCreatorIfNecessary(registry),AopConfigUtils类中,源码如下:
@Nullable private static BeanDefinition registerOrEscalateApcAsRequired(Class> cls, BeanDefinitionRegistry registry, @Nullable Object source) { // -- 断言 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 先判断有没有org.springframework.aop.config.internalAutoProxyCreator // 首次进来,肯定没有 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // -- 将cls也就是InfrastructureAdvisorAutoProxyCreator包装成RootBeanDefinition RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // -- 将beanDefinition注册到IOC容器中,Bean的 // -- 名字就叫org.springframework.aop.config.internalAutoProxyCreator registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
向容器中注入了InfrastructureAdvisorAutoProxyCreator,进入此类,发现父类是AbstractAdvisorAutoProxyCreator,AbstractAdvisorAutoProxyCreator的父类是AbstractAutoProxyCreator,AbstractAutoProxyCreator中的方法,创建并返回了代理类,如下:
/** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */ @Override public Object postProcessAfterInitialization(@Nullable 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; }
给容器中注入InfrastructureAdvisorAutoProxyCreator的主要作用就是,利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象(增强器),代理对象执行方法,利用拦截器链进行调用。
ProxyTransactionManagementConfiguration进入ProxyTransactionManagementConfiguration,部分源码如下:
// -- 向容器中注入名字为TRANSACTION_ADVISOR_BEAN_NAME的切面 @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); // -- 向切面中注入注解解析器,专门来解析事务注解的 advisor.setTransactionAttributeSource(transactionAttributeSource()); // -- 向切面中注入事务的拦截器,专门来拦截方法,包括事务的提交以及回滚操作 advisor.setAdvice(transactionInterceptor()); if (this.enableTx != null) { advisor.setOrder(this.enableTx.getNumber("order")); } return advisor; }
进入transactionAttributeSource()注解解析器,源码如下:
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) { this.publicMethodsOnly = publicMethodsOnly; this.annotationParsers = new LinkedHashSet<>(2); // -- Spring注解的解析器 this.annotationParsers.add(new SpringTransactionAnnotationParser()); if (jta12Present) { // -- jta的解析器 this.annotationParsers.add(new JtaTransactionAnnotationParser()); } if (ejb3Present) { // -- ejb的解析器 this.annotationParsers.add(new Ejb3TransactionAnnotationParser()); } }
进入SpringTransactionAnnotationParser(),部分源码如下:
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")); ArrayListrollBackRules = new ArrayList<>(); Class>[] rbf = attributes.getClassArray("rollbackFor"); for (Class> rbRule : rbf) {
会发现@Transactional中的各种属性都在这里,这样,注解解析器就分析完了
再来看事务的拦截器,分析事务是如何回滚和提交的,进入transactionInterceptor()
@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; }
TransactionInterceptor 是一个实现了MethodInterceptor接口的类,标志着TransactionInterceptor是一个方法拦截器,进入它的invoke()方法
@Override @Nullable public Object invoke(final MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport"s invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }
进入invokeWithinTransaction()
@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); // -- 拿到事务注解信息包括事务的qualifier和rollback信息 final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // -- 获取事务管理器 final PlatformTransactionManager tm = determineTransactionManager(txAttr); // -- 事务连接点的定义信息 final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // 创建并开启事务 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. // -- 调用目标方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception // -- 出现异常了,获取事务管理器,进行事务的回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } // -- 未出现异常,也获取事务管理器则进行事务的提交 commitTransactionAfterReturning(txInfo); return retVal; } .........总结
Spring事务源码梳理
通过注解@EnableTransactionManagement中的@Import(TransactionManagementConfigurationSelector.class)给容器中导入了两个组件,分别是:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
AutoProxyRegistrar:它是一个后置处理器,给容器中注册一个InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象(增强器),代理对象执行方法,利用拦截器链进行调用。
ProxyTransactionManagementConfiguration:给容器中注册事务增强器
事务增强器要用事务注解信息:AnnotationTransactionAttributeSource来解析事务注解
事务拦截器中:transactionInterceptor(),它是一个TransactionInterceptor(保存了事务属性信息和事务管理器),而TransactionInterceptor是一个MethodInterceptor,在目标方法执行的时候,执行拦截器链,事务拦截器(首先获取事务相关的属性,再获取PlatformTransactionManager,如果没有指定任何transactionManager,最终会从容器中按照类型获取一个PlatformTransactionManager,最后执行目标方法,如果异常,便获取到事务管理器进行回滚,如果正常,同样拿到事务管理器提交事务。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/73200.html
摘要:编程式事务指的是通过编码方式实现事务声明式事务基于将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染因此在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件中做相关的事务规则声明,另一种是基于注解的方式。 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式...
摘要:事务管理学习总结时间年月日星期二说明本文部分内容均来自慕课网。一致性一致性指事务前后数据的完整性必须保持一致。声明式事务管理基于的方式很少使用需要为每个进行事务管理的类,配置一个进行增强。 《Spring事务管理》学习总结 时间:2017年2月7日星期二说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com/教学示例源码:https://github.com...
摘要:事务管理结构事务管理有个左右,其中最核心的有个,分别是。事务管理主要结构如下三个核心接口源码解析接口是用于定义一个事务,它定义了事务管理的五大属性,在上一篇文章中有详细介绍。只需要装配一个实体管理工厂接口的任意实现。 1.Spring事务管理API结构 Spring事务管理API有100个左右,其中最核心的API有3个,分别是TransactionDefinition、 Pla...
阅读 3363·2021-11-25 09:43
阅读 2273·2021-09-06 15:02
阅读 3521·2021-08-18 10:21
阅读 3269·2019-08-30 15:55
阅读 2326·2019-08-29 17:06
阅读 3518·2019-08-29 16:59
阅读 947·2019-08-29 13:47
阅读 2710·2019-08-26 13:24