简单使用
引入依赖
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:
- 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();
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切面,一个切面需要包括以下两部分:
- Advice通知:TransactionInterceptor
- Pointcut切点:TransactionAttributeSourcePointcut
TransactionAttributeSourcePointcut
TransactionAttributeSourcePointcut是一个切点,一个切点需要进行两方面的匹配:
- 类的匹配ClassFilter.matches()
- 方法的匹配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在目标方法执行之前开启事务,在目标方法执行之后提交事务,如果出现了异常就会回滚事务。