spring系列-注解驱动原理及源码-声明式事务使用及原理解析
目錄
一、環(huán)境準(zhǔn)備
1、JdbcTemplate使用實例
2、事務(wù)添加
二、聲明式事務(wù)源碼分析
1、原理(與AOP非常相似)
一、環(huán)境準(zhǔn)備
1、JdbcTemplate使用實例
(1)pom文件添加依賴
<!--c3p0數(shù)據(jù)源--> <dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.1</version> </dependency> <!--mysql驅(qū)動--> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.44</version> </dependency> <!--jdbc--> <dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>4.3.12.RELEASE</version> </dependency>(2)創(chuàng)建配置類
package com.xiang.spring.tx;import com.mchange.v2.c3p0.ComboPooledDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; import java.beans.PropertyVetoException;/** * 聲明式事務(wù): * * 環(huán)境搭建: * 1.導(dǎo)入相關(guān)依賴 * 數(shù)據(jù)源、數(shù)據(jù)庫驅(qū)動、SpringJDBC模塊。 * 2.配置數(shù)據(jù)源和JdkcTemplate(spring提供的簡化數(shù)據(jù)庫操作的工具)操作數(shù)據(jù)庫 * */ @ComponentScan("com.xiang.spring.tx") @Configuration public class TxConfig {// 數(shù)據(jù)源@Beanpublic DataSource dataSource() throws PropertyVetoException {ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setUser("root");dataSource.setPassword("123698745");dataSource.setDriverClass("com.mysql.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");return dataSource;}/*** JdbcTemplate操作數(shù)據(jù)庫* spring對@Configuration配置文件有特殊處理,給容器中添加組件的方法,多次調(diào)用都是從容器中找組件,組件只會創(chuàng)建一次。*/@Beanpublic JdbcTemplate jdbcTemplate() throws PropertyVetoException {JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());return jdbcTemplate;} }(3)添加service類和dao類
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;@Service public class UserService {@Autowiredprivate UserDao userDao;public void insetUser() {userDao.insert();System.out.println("插入完成");} } import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository;import java.util.UUID;@Repository public class UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void insert() {String sql = "insert into t_user(username, age) values(?, ?)";String username = UUID.randomUUID().toString().substring(0, 5);jdbcTemplate.update(sql, username, 19);} }(4)測試類查看結(jié)果
import com.xiang.spring.tx.TxConfig; import com.xiang.spring.tx.UserService; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class IOCTest_Tx {@Testpublic void test01() {// 創(chuàng)建ioc容器,容器創(chuàng)建時,默認(rèn)會將單例的bean都創(chuàng)建出來AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);UserService userService = applicationContext.getBean(UserService.class);userService.insetUser();} }2、事務(wù)添加
(1)給方法上標(biāo)注@Transactional,標(biāo)明這個方法是一個事務(wù)方法
/** * 告訴spring這個方法是一個事務(wù)方法 */ @Transactional public void insetUser() {userDao.insert();System.out.println("插入完成");int i = 10/0; }(2)@EnableTransactionManagement開啟基于注解的事務(wù)管理功能
@EnableTransactionManagement @ComponentScan("com.xiang.spring.tx") @Configuration public class TxConfig {(3)配置事務(wù)管理器來管理事務(wù)PlatformTransactionManager
/** * 在容器中注冊事務(wù)管理器 */ @Bean public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException {DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource());return dataSourceTransactionManager; }(4)如果事務(wù)方法報錯,就會回滾。
二、聲明式事務(wù)源碼分析
1、原理(與AOP非常相似)
(1)@EnableTransactionManagement利用TransactionManagementConfigurationSelector給容器中導(dǎo)入組件。
? ? 導(dǎo)入兩個組件AutoProxyRegistrar、ProxyTransactionManagementConfiguration。
(2)AutoProxyRegistrar給容器中注冊一個InfrastructureAdvisorAutoProxyCreator組件。
? ? ①?InfrastructureAdvisorAutoProxyCreator的作用只是利用后置處理器機(jī)制在對象創(chuàng)建以后,包裝對象,返回一個代理對象(增強(qiáng)器),代理對象執(zhí)行方法利用攔截器鏈進(jìn)行調(diào)用。(與AOP類似)
(3)ProxyTransactionManagementConfiguration?做了什么?
? ? ①?給容器中注冊事務(wù)增強(qiáng)器。
?? ?? ? ① 事務(wù)增強(qiáng)器要用事務(wù)注解的信息。用AnnotationTransactionAttributeSource解析事務(wù)注解。
?? ?? ? ②?事務(wù)攔截器。
?? ??? ??? ?TransactionInterceptor保存了事務(wù)的屬性信息以及?事務(wù)管理器。
?? ??? ??? ?TransactionInterceptor是一個MethodInterceptor方法攔截器。
?? ??? ??? ?TransactionInterceptor在目標(biāo)方法執(zhí)行的時候,執(zhí)行攔截器鏈,只有一個事務(wù)攔截器。
?? ??? ?? ? ①?先獲取事務(wù)的屬性。
?? ??? ?? ? ②?再獲取PlatformTransactionManager(平臺事務(wù)管理器),如果事先沒有添加指定任何TransactionManager,最終會從容器中按照類型獲取一個PlatformTransactionManager。
?? ??? ?? ? ③?執(zhí)行目標(biāo)方法,如果異常,獲取到事務(wù)管理器,利用事務(wù)管理器回滾這次操作。
?? ??? ?? ? ④?如果正常,利用事務(wù)管理器提交事務(wù)。
(1)TransactionManagementConfigurationSelector的selectImports方法
@Override protected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY: // 默認(rèn)就是PROXYreturn new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};default:return null;} }(2)ProxyTransactionManagementConfiguration
package org.springframework.transaction.annotation;import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; import org.springframework.transaction.config.TransactionManagementConfigUtils; import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor; import org.springframework.transaction.interceptor.TransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionInterceptor;/** * {@code @Configuration} class that registers the Spring infrastructure beans * necessary to enable proxy-based annotation-driven transaction management. * * @author Chris Beams * @since 3.1 * @see EnableTransactionManagement * @see TransactionManagementConfigurationSelector */ @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();}@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;} }(3)TransactionAspectSupport的invokeWithinTransaction
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)throws Throwable {// If the transaction attribute is null, the method is non-transactional.final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.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 exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}commitTransactionAfterReturning(txInfo);return retVal;}else {// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.try {Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,new TransactionCallback<Object>() {@Overridepublic Object doInTransaction(TransactionStatus status) {TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);try {return invocation.proceedWithInvocation();}catch (Throwable ex) {if (txAttr.rollbackOn(ex)) {// A RuntimeException: will lead to a rollback.if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}else {throw new ThrowableHolderException(ex);}}else {// A normal return value: will lead to a commit.return new ThrowableHolder(ex);}}finally {cleanupTransactionInfo(txInfo);}}});// Check result: It might indicate a Throwable to rethrow.if (result instanceof ThrowableHolder) {throw ((ThrowableHolder) result).getThrowable();}else {return result;}}catch (ThrowableHolderException ex) {throw ex.getCause();}} }(4)TransactionAspectSupport的completeTransactionAfterThrowing,利用事務(wù)管理器回滾
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {if (txInfo != null && txInfo.hasTransaction()) {if (logger.isTraceEnabled()) {logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +"] after exception: " + ex);}if (txInfo.transactionAttribute.rollbackOn(ex)) {try {txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by rollback exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {logger.error("Application exception overridden by rollback exception", ex);throw ex2;}catch (Error err) {logger.error("Application exception overridden by rollback error", ex);throw err;}}else {// We don't roll back on this exception.// Will still roll back if TransactionStatus.isRollbackOnly() is true.try {txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by commit exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {logger.error("Application exception overridden by commit exception", ex);throw ex2;}catch (Error err) {logger.error("Application exception overridden by commit error", ex);throw err;}}} }(5)TransactionAspectSupport的commitTransactionAfterReturning?事務(wù)提交
protected void commitTransactionAfterReturning(TransactionInfo txInfo) {if (txInfo != null && txInfo.hasTransaction()) {if (logger.isTraceEnabled()) {logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");}txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());} }總結(jié)
以上是生活随笔為你收集整理的spring系列-注解驱动原理及源码-声明式事务使用及原理解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring系列-注解驱动原理及源码-自
- 下一篇: springboot项目自定义类在配置文