简单使用

引入依赖

compile("mysql:mysql-connector-java:8.0.23")
compile(project(":spring-jdbc"))

引入spring-jdbc后会自动引入spring-tx事务管理。

配置类

package com.morris.spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
 // 开启事务
public class JdbcConfig {

	@Bean
	public PlatformTransactionManager transactionManager() {
		return new DataSourceTransactionManager(dataSource());
	}

	@Bean
	public JdbcTemplate jdbcTemplate() {
		return new JdbcTemplate(dataSource());
	}

	@Bean
	public DataSource dataSource() {
		String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&allowMultiQueries=true&characterEncoding=UTF-8&useFastDateParsing=false&zeroDateTimeBehavior=convertToNull";
		String username = "root";
		String password = "root";
		return new DriverManagerDataSource(url, username, password);
	}
}

UserDao

package com.morris.spring.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class UserDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public void insert() {
		jdbcTemplate.execute("insert into user(emp_no, login_name, password) values ('xxxoo', 'xxoox', 'ooxxx')");
	}

	public void update() {
		jdbcTemplate.execute("update user set login_name=123455 where user_id=1");
	}
}

JdbcService

package com.morris.spring.service;

import com.morris.spring.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class JdbcService {

	@Autowired
	private UserDao userDao;

	@Transactional
	public void test() {
		userDao.update();
		userDao.insert();
	}

}

测试类

package com.morris.spring.demo.annotation;

import com.morris.spring.config.JdbcConfig;
import com.morris.spring.dao.UserDao;
import com.morris.spring.service.JdbcService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class JdbcDemo {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
		applicationContext.register(JdbcConfig.class);
		applicationContext.register(UserDao.class);
		applicationContext.register(JdbcService.class);
		applicationContext.refresh();
		JdbcService jdbcService = applicationContext.getBean(JdbcService.class);
		jdbcService.test();
	}

}

实现原理

@EnableTransactionManagement

@EnableTransactionManagement注解用来开启Spring的声明式事务,那么这个注解到底有什么用呢?先来看看这个注解的声明:

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

可以@EnableTransactionManagement注解上面的@Import导入了一个类TransactionManagementConfigurationSelector。

TransactionManagementConfigurationSelector

顾名思义,TransactionManagementConfigurationSelector从名称上就可以看出其本质是一个Selector,而Selector最重要的方法为selectImports()。

org.springframework.transaction.annotation.TransactionManagementConfigurationSelector#selectImports

protected String[] selectImports(AdviceMode adviceMode) {
	switch (adviceMode) {
		case PROXY: // 事务走这
			// 一个Registrar
			// 一个Configuration
			return new String[] {AutoProxyRegistrar.class.getName(),
					ProxyTransactionManagementConfiguration.class.getName()};
		case ASPECTJ:
			return new String[] {determineTransactionAspectClass()};
		default:
			return null;
	}
}

selectImports()又导入了两个类,AutoProxyRegistrar和ProxyTransactionManagementConfiguration。

ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration向容器中注入了3个Bean:

  1. BeanFactoryTransactionAttributeSourceAdvisor
  2. TransactionAttributeSource
  3. 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();
		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(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

AutoProxyRegistrar

顾名思义,AutoProxyRegistrar从名称上就可以看出其本质是一个ImportBeanDefinitionRegistrar,而ImportBeanDefinitionRegistrar最重要的方法为registerBeanDefinitions(),这个方法的主要作用就是用方法参数中的registry向容器中注入一些BeanDefinition。

org.springframework.context.annotation.AutoProxyRegistrar#registerBeanDefinitions

–> org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry)

–> org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

public static BeanDefinition registerAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

总结:AutoProxyRegistrar.registerBeanDefinitions()往容器中注入了一个类InfrastructureAdvisorAutoProxyCreator。

InfrastructureAdvisorAutoProxyCreator

InfrastructureAdvisorAutoProxyCreator与AOP注入的AnnotationAwareAspectJAutoProxyCreator一样是一个BeanPostProcessor,主要逻辑在postProcessAfterInitialization()。

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		// 先从缓存中获取代理对象
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			// 按需生成代理对象
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

这一段与AOP的处理方式是一样,只不过生成的代理类中通知只有BeanFactoryTransactionAttributeSourceAdvisor。

BeanFactoryTransactionAttributeSourceAdvisor

顾名思义BeanFactoryTransactionAttributeSourceAdvisor是一个Advisor切面,一个切面需要包括以下两部分:

  1. Advice通知:TransactionInterceptor
  2. Pointcut切点:TransactionAttributeSourcePointcut

TransactionAttributeSourcePointcut

TransactionAttributeSourcePointcut是一个切点,一个切点需要进行两方面的匹配:

  1. 类的匹配ClassFilter.matches()
  2. 方法的匹配MethodMatcher.matches()

ClassFilter.matches()理论上来说是要匹配类上面的@Transaction注解,实际上啥也没有操作,具体的逻辑都在方法的匹配上面。

org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut.TransactionAttributeSourceClassFilter

private class TransactionAttributeSourceClassFilter implements ClassFilter {

	@Override
	public boolean matches(Class<?> clazz) {
		if (TransactionalProxy.class.isAssignableFrom(clazz) ||
				TransactionManager.class.isAssignableFrom(clazz) ||
				PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
			return false;
		}
		// 看了半天没啥用,全部返回true
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.isCandidateClass(clazz));
	}
}

MethodMatcher.matches()就是匹配目标方法上面有没有@Transaction注解,如有就返回true。

org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches

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

TransactionInterceptor

TransactionInterceptor从继承关系上面可以实现了Advice接口,所有目标方法的执行都会先经过TransactionInterceptor.invoke()。

org.springframework.transaction.interceptor.TransactionInterceptor#invoke

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

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
		final InvocationCallback invocation) throws Throwable {

	// If the transaction attribute is null, the method is non-transactional.
	// 类型为AnnotationTransactionAttributeSource,在ProxyTransactionManagementConfiguration中注入的
	// 主要用来解析@Transaction注解
	TransactionAttributeSource tas = getTransactionAttributeSource();
	// 将目标方法上@Transaction注解中的属性封装为RuleBasedTransactionAttribute,可以理解为一个Map
	/**
	 * @see AbstractFallbackTransactionAttributeSource#getTransactionAttribute(java.lang.reflect.Method, java.lang.Class)
	 */
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

	// 获取事务管理器,从JdbcConfig中注入DataSourceTransactionManager
	final TransactionManager tm = determineTransactionManager(txAttr);
... ...
	// 事务管理器
	PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
		// DataSourceTransactionManager不是CallbackPreferringPlatformTransactionManager
		// Standard transaction demarcation with getTransaction and commit/rollback calls.
		// 创建事务
		TransactionInfo txInfo = createTransactionIfNecessary(ptm, 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);
		}

		if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
			// Set rollback-only in case of Vavr failure matching our rollback rules...
			TransactionStatus status = txInfo.getTransactionStatus();
			if (status != null && txAttr != null) {
				retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
			}
		}

		// 提交事务
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}
... ...
}

TransactionInterceptor其实就是利用AOP在目标方法执行之前开启事务,在目标方法执行之后提交事务,如果出现了异常就会回滚事务。