• 【spring 注解驱动开发】spring事务处理原理


    尚学堂spring 注解驱动开发学习笔记之 - 事务处理

    事务处理

    1、事务处理实现

    实现步骤:

     * 声明式事务:
     * 
     * 环境搭建:
     * 1、导入相关依赖
     * 		数据源、数据库驱动、Spring-jdbc模块
     * 2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
     * 3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
     * 4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
     * 		@EnableXXX
     * 5、配置事务管理器来控制事务;
     * 		@Bean
     * 		public PlatformTransactionManager transactionManager()
    

    代码实现:

    @EnableTransactionManagement
    @ComponentScan("com.atguigu.tx")
    @Configuration
    public class TxConfig {
    	
    	//数据源
    	@Bean
    	public DataSource dataSource() throws Exception{
    		ComboPooledDataSource dataSource = new ComboPooledDataSource();
    		dataSource.setUser("root");
    		dataSource.setPassword("123456");
    		dataSource.setDriverClass("com.mysql.jdbc.Driver");
    		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
    		return dataSource;
    	}
    	
    	@Bean
    	public JdbcTemplate jdbcTemplate() throws Exception{
    		//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
    		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
    		return jdbcTemplate;
    	}
    	
    	//注册事务管理器在容器中
    	@Bean
    	public PlatformTransactionManager transactionManager() throws Exception{
    		return new DataSourceTransactionManager(dataSource());
    	}
    } 

    2、事务处理原理

    原理分析:

     * 原理:
     * 1)、@EnableTransactionManagement
     * 			利用TransactionManagementConfigurationSelector给容器中会导入组件
     * 			导入两个组件
     * 			AutoProxyRegistrar
     * 			ProxyTransactionManagementConfiguration
     * 2)、AutoProxyRegistrar:
     * 			给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
     * 			InfrastructureAdvisorAutoProxyCreator:?
     * 			利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
     * 
     * 3)、ProxyTransactionManagementConfiguration 做了什么?
     * 			1、给容器中注册事务增强器;
     * 				1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解
     * 				2)、事务拦截器:
     * 					TransactionInterceptor;保存了事务属性信息,事务管理器;
     * 					他是一个 MethodInterceptor;
     * 					在目标方法执行的时候;
     * 						执行拦截器链;
     * 						事务拦截器:
     * 							1)、先获取事务相关的属性
     * 							2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
     * 								最终会从容器中按照类型获取一个PlatformTransactionManager;
     * 							3)、执行目标方法
     * 								如果异常,获取到事务管理器,利用事务管理回滚操作;
     * 								如果正常,利用事务管理器,提交事务
     * 			
     */
    

    核心代码

    1、EnableTransactionManagement注解,注入TransactionManagementConfigurationSelector类

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(TransactionManagementConfigurationSelector.class)
    public @interface EnableTransactionManagement {
    

    2、TransactionManagementConfigurationSelector类,最终会导入AutoProxyRegistrar.class和ProxyTransactionManagementConfiguration.class两个组件。

    public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    
    	/**
    	 * Returns {@link ProxyTransactionManagementConfiguration} or
    	 * {@code AspectJ(Jta)TransactionManagementConfiguration} 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[] {determineTransactionAspectClass()};
    			default:
    				return null;
    		}
    	}
    
    	private String determineTransactionAspectClass() {
    		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
    				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
    				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
    	}
    
    }
    

    3、AutoProxyRegistrar类的作用为:

      给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;

      最终的目的是:利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;

    @Override
    	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    		boolean candidateFound = false;
    		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
    		for (String annType : annTypes) {
    			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
    			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;
    					}
    				}
    			}
    		}
    		if (!candidateFound && logger.isInfoEnabled()) {
    			String name = getClass().getSimpleName();
    			logger.info(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));
    		}
    	}
    

    InfrastructureAdvisorAutoProxyCreator类的作用与AnnotationAwareAspectJAutoProxyCreator类的作用类似。可参考:【spring 注解驱动开发】Spring AOP原理

    @SuppressWarnings("serial")
    public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
    		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    

    4、ProxyTransactionManagementConfiguration类

    代理事务管理配置类

    @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());
    		if (this.enableTx != null) {
    			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;
    	}
    
    }
    

    TransactionInterceptor类,事务调用:invokeWithinTransaction()方法为最终执行的方法

    @Override
    	@Nullable
    	public Object invoke(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);
    	}
    

    TransactionAspectSupport类的最终事务方法执行:

    @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();
    		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)) {
    			// Standard transaction demarcation with getTransaction and commit/rollback calls.
    			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    
    			Object retVal;
    			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;
    		}
    
    		else {
    			final ThrowableHolder throwableHolder = new ThrowableHolder();
    
    			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
    			try {
    				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, 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.
    							throwableHolder.throwable = ex;
    							return null;
    						}
    					}
    					finally {
    						cleanupTransactionInfo(txInfo);
    					}
    				});
    
    				// Check result state: It might indicate a Throwable to rethrow.
    				if (throwableHolder.throwable != null) {
    					throw throwableHolder.throwable;
    				}
    				return result;
    			}
    			catch (ThrowableHolderException ex) {
    				throw ex.getCause();
    			}
    			catch (TransactionSystemException ex2) {
    				if (throwableHolder.throwable != null) {
    					logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
    					ex2.initApplicationException(throwableHolder.throwable);
    				}
    				throw ex2;
    			}
    			catch (Throwable ex2) {
    				if (throwableHolder.throwable != null) {
    					logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
    				}
    				throw ex2;
    			}
    		}
    	}
    
  • 相关阅读:
    Cannot get a NUMERIC value from a STRING cell? 已解决
    Android Studio快捷键大全
    mysql索引
    eclipse中出现错误 Syntax error, insert "}" to complete Block
    function
    IGS OPC UA 配置
    IFIX 5.9 历史数据 曲线 (非SQL模式)
    IFIX 5.9 报警存sql
    IFIX 数据源 节点 标签 域名
    IFIX 目录结构
  • 原文地址:https://www.cnblogs.com/wjqhuaxia/p/12261111.html
Copyright © 2020-2023  润新知