spring事务之二 --spring事务的aop实现

上文交代了spring事务的一些基本的概念和比较重要的类。然后通过问题的方式先粗略的交代一些spring的事务一些方面。本文将从spring tx在spring系统中如何生效这个角度来思考spring事务这件事情。

说道事务,首先是联想到了数据库。数据库会根据我们设置的事务属性去做事务这件事情。那么,我们如何将事务配置到spring体系中的呢?

1、注解形式

xml中启动@Transactional注解扫描
  <tx:annotation-driven transaction-manager="transactionManager" />
  @Transactional(propagation=Propagation.REQUIRED)
public void save(User user){
    xxxx
}

2、代理工厂形式

<bean id="proxy"
   class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <!-- 为事务代理工厂Bean注入事务管理器 -->
    <property name="transactionManager" ref="transactionManager" />
    <!-- 要在哪个Bean上面创建事务代理对象 -->
    <property name="target" ref="productDao" />
    <!-- 指定事务属性 -->
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

3、aop形式

<tx:advice id="txAdvice" transaction-manager="transactionManager">  
    <tx:attributes>  
        <tx:method name="add*" propagation="REQUIRED" />  
        <tx:method name="delete*" propagation="REQUIRED" />  
        <tx:method name="update*" propagation="REQUIRED" />  
        <tx:method name="add*" propagation="REQUIRED" />    
    </tx:attributes>  
</tx:advice>  

<aop:config>  
    <aop:pointcut id="pointcut" 
        expression="XXXX" />  
    <aop:advisor advice-ref="txAdvice" 
        pointcut-ref="pointcut" />  
</aop:config>

不管是aop实现的也好,还是我们自己生成代理类采用事务拦截器实现事务也好,其实思想都是一致的。下面我们着重说说aop事务代理是如何实现的。上面的第一种和第三种都是使用了aop去实现。我们将从以下事务和aop分别都做了什么,然后再结合两者看看事务是如何实现的。

拿@Transaction来举例。注解形式包含两个方面

1、事务开启标签配置

2、方法上的事务标签

事务开启做了什么?

从标签解析器中我们不难发现事务开启标签做了以下这件事情 --- 将标签解析成adivosr的形式注入到spring容器中。 输入图片说明

那么当我们在方法头上写了事务标签的时候如何感知事务的呢?

1、注解解析

在我们将标签解析成adivosr的过程中,我们也将一个解析类SpringTransactionAnnotationParser注入到了注解标签中。

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		this.annotationParsers = new LinkedHashSet<>(2);
		this.annotationParsers.add(new SpringTransactionAnnotationParser());
		if (jta12Present) {
			this.annotationParsers.add(new JtaTransactionAnnotationParser());
		}
		if (ejb3Present) {
			this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
		}
	}
	

该注解解析器能够将@Transaction标签解析成类实例TransactionAttribute

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
		if (ae.getAnnotations().length > 0) {
			for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
				TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
				if (attr != null) {
					return attr;
				}
			}
		}
		return null;
	}

拦截器会找到这个方法去获得相应的事务属性。

2、什么时候将有注解的类包装成了代理 有了事务属性,也有了切点和拦截器。接下来就是aop要做的事情了。

spring在解析xml的时候会找到类BeanNameAutoProxyCreator,该类的父类实现了接口BeanPostProcessor,那么在每一个类初始化的时候都要走该方法。

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

该方法首先找到容器中的advisor类型的实例,然后根据切点筛选该bean符合要求的advisor。如果找到的advisor不为空,则创建对象的aop代理返回。

	protected Object createProxy(
			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
//在ConfigurableListableBeanFactory类型的容器中,将被代理类的bean属性AutoProxyUtils.originalTargetClass设为为被代理类类。
		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数组
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		//遍历advisor数组,将其放置到代理工厂中
		for (Advisor advisor : advisors) {
			proxyFactory.addAdvisor(advisor);
		}
//设置被代理源
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);
//代理是否被冻结属性设置
		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
		}
//创建该bean的代理。
		return proxyFactory.getProxy(getProxyClassLoader());
	}

该类还有一个地方创建了代理

输入图片说明

这个地方是工厂在创建对象,获得指定bean的早起访问,为了解决循环引用的问题。

输入图片说明

至此,那些配置到BeanNameAutoProxyCreator类中的service类将被代理成了apring的aop代理了。那么就差最后一步,在这些代理类被访问的时候,aop是该如何做才走了事务逻辑呢?

3、aop代理解析过程

由于service一般都有实现了接口类,所以代理是走的jdk代理。接下来的逻辑我都只看jdk代理。

JdkDynamicAopProxy类实现了InvocationHandler,所以当代理类被访问的时候,会首先进入方法invoke中。

输入图片说明

输入图片说明

输入图片说明

事务的拦截器不是InterceptorAndDynamicMethodMatcher类型的,那么会直接执行事务拦截器逻辑。 输入图片说明输入图片说明

输入图片说明

输入图片说明

输入图片说明

至此aop就完成了事务逻辑的处理。

总结下整个过程:

1、配置文件将aop的advice、pointcut注入到spring容器中。使用类BeanNameAutoProxyCreator 将要进行事务逻辑的类生产aop代理。

2、在访问aop代理类的时候会走拦截器链,当走到事务拦截器时会生产事务属性,根据事务属性生成事务。

3、拦截器链继续执行直到结束,事务拦截器会根据返回的结果类型,如果报错则根据事务属性配置回滚事务,如果顺利完成则根据事务属性将事务从当前线程中删除。

4、最后提交事务,操作数据库的connection.commit方法将我们执行的sql语句提交到数据库中,完成所有操作。

参考文献

https://my.oschina.net/pingpangkuangmo/blog/416038

欢迎加入qq群: 122567875 欢迎关注微信公众号:hyssop的后花园

转载于:https://my.oschina.net/zjItLife/blog/749852

在车辆工程中,悬架系统的性能评估和优化一直是研究的热点。悬架不仅关乎车辆的乘坐舒适性,还直接影响到车辆的操控性和稳定性。为了深入理解悬架的动态行为,研究人员经常使用“二自由度悬架模型”来简化分析,并运用“传递函数”这一数学工具来描述悬架系统的动态特性。 二自由度悬架模型将复杂的车辆系统简化为两个独立的部分:车轮和车身。这种简化模型能够较准确地模拟出车辆在垂直方向上的运动行为,同时忽略了侧向和纵向的动态影响,这使得工程师能够更加专注于分析与优化与垂直动态相关的性能指标。 传递函数作为控制系统理论中的一种工具,能够描述系统输入和输出之间的关系。在悬架系统中,传递函数特别重要,因为它能够反映出路面不平度如何被悬架系统转化为车内乘员感受到的振动。通过传递函数,我们可以得到一个频率域上的表达式,从中分析出悬架系统的关键动态特性,如系统的振幅衰减特性和共振频率等。 在实际应用中,工程师通过使用MATLAB这类数学软件,建立双质量悬架的数学模型。模型中的参数包括车轮质量、车身质量、弹簧刚度以及阻尼系数等。通过编程求解,工程师可以得到悬架系统的传递函数,并据此绘制出传递函数曲线。这为评估悬架性能提供了一个直观的工具,使工程师能够了解悬架在不同频率激励下的响应情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值