8.2-spring 事务-声明式事务(@Transactional原理)
8.2-spring 事务-声明式事务(@Transactional原理)
在 8.1-spring 事务-声明式事务(使用) 一文中我们了解到 spring 通过 @Transactional 注解实现事务的操作,开发者只需要关注具体业务,而事务操作是通过 spring aop 实现的,即给使用了 @Transactional 注解的类生成代理类,然后执行具体的事务操作。生成代理类后执行事务的方式和 jdbc 提供的编程式事务方式类似,可以通过 jdbc 提供的事务 这篇文章查看详情。
何时生成代理类
spring 通过 AOP 生成代理类,了解 AOP 知识之前需要了解 IOC 相关知识点。IOC 即将对象的创建和销毁交给容器管理,简单点讲可以分为以下步骤:
- 解析bean
- 注册bean
- 实例化bean
而 AOP 创建代理类是在实例化bean后对原有bean进行加强,一般通过 BeanPostProcessor 的后置方法 postProcessAfterInstantiation 实现。
① 解析bean并注册 BeanPostProcessor 和切点通知类
1) spring/springboot 通过 ConfigurationClassPostProcessor.parse 解析 .class 文件,查找包含 @Component、@Service 等类似注解的类,将这些类注册到容器,同时查找包含 @Import 注解的类,这里以事务注解 EnableTransactionManagement 举例:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {boolean proxyTargetClass() default false;AdviceMode mode() default AdviceMode.PROXY;int order() default Integer.MAX_VALUE;
}
解析 @Import 具体方法在 ConfigurationClassParser 类 doProcessConfigurationClass 方法中
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
2)找到 @Import 注解的值并实例化,这里是 TransactionManagementConfigurationSelector:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {public TransactionManagementConfigurationSelector() {}protected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[]{this.determineTransactionAspectClass()};default:return null;}}private String determineTransactionAspectClass() {return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";}
}
该代码也在 processImports 方法中,实例化后调用 selectImports 方法:
3)调用 selectImports 方法后获取列名称返回值,这里是 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration ,再次调用 processImports 方法,
实例化 org.springframework.context.annotation.AutoProxyRegistrar(实例化后后面会用到)
解析 ProxyTransactionManagementConfiguration (后续会将里面的bean注册到容器中)
ProxyTransactionManagementConfiguration:
package org.springframework.transaction.annotation;@Configuration(proxyBeanMethods = false
)
@Role(2)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {public ProxyTransactionManagementConfiguration() {}@Bean(name = {"org.springframework.transaction.config.internalTransactionAdvisor"})@Role(2)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource);advisor.setAdvice(transactionInterceptor);if (this.enableTx != null) {advisor.setOrder((Integer)this.enableTx.getNumber("order"));}return advisor;}@Bean@Role(2)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}@Bean@Role(2)public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource);if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}
}
4)注册上述bean到容器
调用的是ConfigurationClassPostProcessor 类 processConfigBeanDefinitions 方法里面的 this.reader.loadBeanDefinitions(configClasses); 方法,在这个方法里会调用 AutoProxyRegistrar 的 registerBeanDefinitions 方法
这里会注册 一个 InfrastructureAdvisorAutoProxyCreator 类到容器中:
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {@Nullableprivate ConfigurableListableBeanFactory beanFactory;public InfrastructureAdvisorAutoProxyCreator() {}protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.initBeanFactory(beanFactory);this.beanFactory = beanFactory;}protected boolean isEligibleAdvisorBean(String beanName) {return this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == 2;}
}
它是一个 BeanPostProcessor 类型
② 使用 BeanPostProcessor(InfrastructureAdvisorAutoProxyCreator) 生成代理类
1) 上述 bean 注册完成后会随着 IOC 容器实例化,包括 InfrastructureAdvisorAutoProxyCreator(BeanPostProcessor,在此类 postProcessAfterInstantiation 方法生成代理类对象),BeanFactoryTransactionAttributeSourceAdvisor (@Transactional 切点和通知),TransactionInterceptor (通知的具体实现方式,即拦截后的处理操作)
2)生成代理类对象
调用 AbstractAutoProxyCreator类的 postProcessAfterInitialization 方法,
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = this.getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 调用此方法return this.wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;} else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;} else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {// 在这里会判断当前类 UserService 符不符合 @Transactional 切点,// 由于 UserService 加了事务注解,所以 specificInterceptors 不为空,即会创建 UserService 的代理对象Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);// 在此创建代理对象Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;} else {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}} else {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}
}
在 getAdvicesAndAdvisorsForBean 方法中会调用 TransactionAttributeSourcePointcut 类的 matches 方法判断被代理类的方法有没有加@Transactional注解,即是否符合事务的切点
@Nullableprotected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}
使用事务
调用加了spring事务的方法时,spring会调用切点通知的方法,这里是 TransactionInterceptor 类的 invoke 方法
package org.springframework.transaction.interceptor;
。。。。 省略 。。。。
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {。。。。 省略 。。。。@Nullablepublic Object invoke(final MethodInvocation invocation) throws Throwable {Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new TransactionAspectSupport.CoroutinesInvocationCallback() {@Nullablepublic Object proceedWithInvocation() throws Throwable {return invocation.proceed();}public Object getTarget() {return invocation.getThis();}public Object[] getArguments() {return invocation.getArguments();}});}。。。。 省略 。。。。
}
执行事务的具体操作在其父类 TransactionAspectSupport invokeWithinTransaction 方法中
上述讲解只是列出了一些关键性的步骤,如果需要了解各个细节需要对 IOC 容器非常熟悉,强烈建议自行阅读源码,也可以通过SpringBoot源码解析(1.4)-自动装配原理(总结) 这篇文章了解