spring事务-创建代理对象

用来开启事务的注解@EnableTransactionManagement上通过@Import导入了TransactionManagementConfigurationSelector组件,TransactionManagementConfigurationSelector类的父类AdviceModeImportSelector实现了ImportSelector接口,因此会调用public final String[] selectImports(AnnotationMetadata importingClassMetadata)方法注册Bean定义,此时会调用子类TransactionManagementConfigurationSelector中的selectImports()方法导入AutoProxyRegistrar和ProxyTransactionManagementConfiguration组件。

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

属性mode的默认值是AdviceMode.PROXY,因此回导入AutoProxyRegistrar组件和ProxyTransactionManagementConfiguration组件。

	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;
		}
	}

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口中声明的registerBeanDefinitions()方法,此时会向容器中注册InfrastructureAdvisorAutoProxyCreator组件,这个组件的作用就是找到当前容器中的通知,再使用通知创建目标类的代理对象。
ProxyTransactionManagementConfiguration类是个使用了@Configuration注解的配置,通过@Bean注解创建了

  • BeanFactoryTransactionAttributeSourceAdvisor
  • TransactionAttributeSource
  • TransactionInterceptor。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		......
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		......
	}

}

InfrastructureAdvisorAutoProxyCreator类的父类AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation(),因此在Bean实例化的时候会被调用。shouldSkip()中会调用BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans()方法从容器找到实现了Advisor接口的Bean,即BeanFactoryTransactionAttributeSourceAdvisor

	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}
.....
	}

读过aop的源码后我们知道,每个通知都包含切点表达式和拦截器,BeanFactoryTransactionAttributeSourceAdvisor的拦截器就是TransactionInterceptor,此拦截器会在调用目标方法时生效,而切点表达式Pointcut为

	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};

InfrastructureAdvisorAutoProxyCreator类的父类AbstractAutoProxyCreator实现了BeanPostProcessor接口的postProcessAfterInitialization()方法,创建代理对象的过程与aop类似,获取能作用在当前Bean上面的通知,再使用通知生成代理对象。

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		......

		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			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;
	}

首先看通知的获取,首先获取容器内所有的通知,然后通过AopUtils#canApply()找到能应用在当前方法上的通知。

	public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<>();
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

事务对应的切点为TransactionAttributeSourcePointcut,TransactionAttributeSourcePointcut的父类StaticMethodMatcherPointcut#getMethodMatcher()返回的就是TransactionAttributeSourcePointcut实例对象本身。

// StaticMethodMatcherPointcut
	@Override
	public final MethodMatcher getMethodMatcher() {
		return this;
	}

然后调用自身的TransactionAttributeSourcePointcut#matches()方法对目标类和目标方法进行判断,是否可以应用通知。getTransactionAttributeSource()返回的是注入到BeanFactoryTransactionAttributeSourceAdvisor组件中的TransactionAttributeSource属性,默认是AnnotationTransactionAttributeSource实现的。

	public boolean matches(Method method, Class<?> targetClass) {
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

然后调用AnnotationTransactionAttributeSource的父类AbstractFallbackTransactionAttributeSource#getTransactionAttribute()获取作用在方法上的@Transactional注解属性。

	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		......
		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.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}

首先尝试获取作用在方法上的@Transactional,没有获取到则获取作用在类上的@Transactional注解,

	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// 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 = AopUtils.getMostSpecificMethod(method, targetClass);

		// 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;
	}

AnnotationTransactionAttributeSource内部存在SpringTransactionAnnotationParser用来解析@Transactional注解,使用RuleBasedTransactionAttribute封装@Transactional注解属性。

// SpringTransactionAnnotationParser.java
	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"));

		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}

至此我们找到了可以应用的通知,接下来就是代理对象的创建了,设置拦截器为DynamicAdvisedInterceptor,当通过代理对象调用方法时就会调用intercept()进行拦截。

	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		return proxyFactory.getProxy(getProxyClassLoader());
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编辑推荐: 本文来自于csdn,本篇文章主要介绍了LCN5.0.2有3种模式,分别是LCN模式,TCC模式,TXC模式,希望对您的学习 有所帮助。 一、简介 LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果。 LCN模式: LCN模式是通过代理Connection的方式实现对本地事务的操作,然后在由TxManager统一协调控制事务。当本地事务提交回滚或者关闭连接时将会执行假操作,该代理的连接将由LCN连接池管理。 该模式的特点: - 该模式对代码的嵌入性为低。 - 该模式仅限于本地存在连接对象且可通过连接对象控制事务的模块。 - 该模式下的事务提交与回滚是由本地事务方控制,对于数据一致性上有较高的保障。 - 该模式缺陷在于代理的连接需要随事务发起方一共释放连接,增加了连接占用的时间。 TCC模式: TCC事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。 该模式的特点: - 该模式对代码的嵌入性高,要求每个业务需要写三种步骤的操作。 - 该模式对有无本地事务控制都可以支持使用面广。 - 数据一致性控制几乎完全由开发者控制,对业务开发难度要求高。 TXC模式: TXC模式命名来源于淘宝,实现原理是在执行SQL之前,先查询SQL的影响数据,然后保存执行的SQL快走信息和创建锁。当需要回滚的时候就采用这些记录数据回滚数据库,目前锁实现依赖redis分布式锁控制。 该模式的特点: - 该模式同样对代码的嵌入性低。 - 该模式仅限于对支持SQL方式的模块支持。 - 该模式由于每次执行SQL之前需要先查询影响数据,因此相比LCN模式消耗资源与时间要多。 - 该模式不会占用数据库的连接资源。 二、原理 核心步骤 1.创建事务组 是指在事务发起方开始执行业务代码之前先调用TxManager创建事务对象,然后拿到事务标示GroupId的过程。 2.添加事务组 添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息添加通知给TxManager的操作。 3.关闭事务组 是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager的动作。当执行完关闭事务组的方法以后,TxManager将根据事务组信息来通知相应的参与模块提交或回滚事务事务控制原理 LCN事务控制原理是由事务模块TxClient下的代理连接池与TxManager的协调配合完成的事务协调控制。 TxClient的代理连接池实现了javax.sql.DataSource接口,并重写了close方法,事务模块在提交关闭以后TxClient连接池将执行"假关闭"操作,等待TxManager协调完成事务以后在关闭连接。 对于代理连接池的优化 自动超时机制,任何通讯都有最大超时限制,参与模块在等待通知的状态下也有最大超时限制,当超过时间限制以后事务模块将先确认事务状态,然后再决定执行提交或者回滚操作,主要为了给最大资源占用时间加上限制。 智能识别创建不同的连接 对于只读操作、非事务操作LCN将不开启代理功能,返回本地连接对象,对于补偿事务的启动方将开启回滚连接对象,执行完业务以后马上回滚事务。 LCN连接重用机制 当模块在同一次事务下被重复执行时,连接资源会被重用,提高连接的使用率。 事务补偿机制 为什么需要事务补偿? 事务补偿是指在执行某个业务方法时,本应该执行成功的操作却因为服务器挂机或者网络抖动等问题导致事务没有正常提交,此种场景就需要通过补偿来完成事务,从而达到事务的一致性。 补偿机制的触发条件? 当执行关闭事务组步骤时,若发起方接受到失败的状态后将会把该次事务识别为待补偿事务,然后发起方将该次事务数据异步通知给TxManager。TxManager接受到补偿事务以后先通知补偿回调地址,然后再根据是否开启自动补偿事务状态来补偿或保存该次切面事务数据。 补偿事务机制 LCN的补偿事务原理是模拟上次失败事务的请求,然后传递给TxClient模块然后再次执行该次请求事务。 模拟场景演示 若存在事务发起方、参与方A、参与方B。调用关系图如下 那么他们正常执行业务的时序图为: 若参与方B出现异常,那么他们的业务时序图为: 若他们的调用关系是这样的情况 此时发生参与方B出现异常时他们的时序图为: 三、使用 环境: SpringBoot 2.0.
Spring的动态代理事务是两个关键的概念。让我先解释一下它们各自的含义,然后再谈论它们之间的关系。 动态代理是一种设计模式,它允许程序在运行时为一个接口创建一个代理对象。这意味着你可以在不改变原始类代码的情况下,通过代理对象来执行额外的操作。Spring框架使用了动态代理来实现AOP(面向切面编程)功能,通过在原始对象的方法执行前后插入切面逻辑,实现了横切关注点的解耦。 事务是指一组数据库操作,它们要么全部成功执行,要么全部回滚到初始状态,以保持数据的一致性。在Spring中,事务管理是通过AOP实现的。通过在方法或类上添加事务注解,Spring可以自动管理事务的开始、提交或回滚。这样,你可以轻松地将事务逻辑与业务逻辑分离开来,使代码更加清晰和可维护。 动态代理事务之间的关系在于,Spring使用动态代理创建事务代理对象。当你在方法或类上添加事务注解时,Spring会在运行时动态地创建一个代理对象,并在方法执行前后添加事务管理的逻辑。这样,当方法被调用时,事务代理对象会负责处理事务的开始、提交或回滚,以保证数据的一致性。 总结一下,动态代理Spring实现AOP的一种机制,而事务则是通过AOP和动态代理来实现的。它们共同为应用程序提供了更好的可扩展性、可维护性和可测试性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值