了解了Spring AOP执行过程,再看Spring事务源码其实非常简单。
首先从简单使用开始, 演示Spring事务使用过程
Xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql:///custom_db" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- transactionManager 对象 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* org.spring.tx.dao.*.*(..))"></aop:advisor>
</aop:config>
<bean id="userDao" class="org.spring.tx.dao.UserDaoImpl">
<constructor-arg index="0" ref="jdbcTemplate"></constructor-arg>
</bean>
</beans>
实体类:
package org.spring.tx.dto;
public class UserDto {
private Long id;
private String UserName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return UserName;
}
public void setUserName(String userName) {
UserName = userName;
}
}
业务Dao类:
package org.spring.tx.dao;
import org.spring.tx.dto.UserDto;
public interface UserDao {
void insert(UserDto userDto);
}
package org.spring.tx.dao;
import org.spring.tx.dto.UserDto;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDaoImpl implements UserDao {
//注入 JdbcTemplate
private JdbcTemplate jdbcTemplate;
public UserDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void insert(UserDto userDto) {
//创建 sql 语句
String sql = "insert into user (username)values(?)";
//调用方法实现
Object[] args = {userDto.getUserName()};
//返回影响行数
int update = jdbcTemplate.update(sql,args);
System.out.println("user新增条数:" + update);
//throw new RuntimeException("业务出错了!!!");
}
}
测试代码:
package org.spring.tx;
import org.spring.tx.dao.UserDao;
import org.spring.tx.dto.UserDto;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-tx.xml");
applicationContext.start();
UserDao userDao = applicationContext.getBean(UserDao.class);
UserDto userDto = new UserDto();
userDto.setUserName("zhangsan");
userDao.insert(userDto);
applicationContext.stop();
}
}
执行结果:
==================从源码角度简单分析一下=====================
根据Spring AOP过程(参考:Spring AOP源码篇二之 代理工厂ProxyFactory学习-CSDN博客 Spring AOP源码篇三之 xml配置-CSDN博客),增强工作由Advice完成,而事务的Advice对应的是TransactionInterceptor.
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public TransactionInterceptor() {
}
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
setTransactionManager(ptm);
setTransactionAttributes(attributes);
}
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
//TransactionInterceptor实现了Advice(MethodInterceptor)接口,增强工作由该方法完成
//核心代码,方法调用入口
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 父类TransactionAspectSupport中方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void writeObject(ObjectOutputStream oos) throws IOException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
oos.defaultWriteObject();
// Deserialize superclass fields.
oos.writeObject(getTransactionManagerBeanName());
oos.writeObject(getTransactionManager());
oos.writeObject(getTransactionAttributeSource());
oos.writeObject(getBeanFactory());
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
ois.defaultReadObject();
// Serialize all relevant superclass fields.
// Superclass can't implement Serializable because it also serves as base class
// for AspectJ aspects (which are not allowed to implement Serializable)!
setTransactionManagerBeanName((String) ois.readObject());
setTransactionManager((PlatformTransactionManager) ois.readObject());
setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
setBeanFactory((BeanFactory) ois.readObject());
}
}