Spring的事務(wù)管理之聲明式事務(wù)詳解
Spring的事務(wù)管理介紹
在Spring中,事務(wù)也是用 AOP 切面技術(shù)來實現(xiàn)的,有兩種實現(xiàn)方式:
- 聲明式事務(wù)管理: 基于
Spring AOP實現(xiàn)。其本質(zhì)是對方法前后進(jìn)行攔截,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。 - 編程式事務(wù)管理: 編程式事務(wù)管理使用
TransactionTemplate可實現(xiàn)更細(xì)粒度的事務(wù)控制。
聲明式事務(wù)管理不需要入侵代碼,通過@Transactional就可以進(jìn)行事務(wù)操作,更快捷而且簡單且大部分業(yè)務(wù)都可以滿足,推薦使用。
其實不管是編程式事務(wù)還是聲明式事務(wù),最終調(diào)用的底層核心代碼是一致的。
聲明式事務(wù)管理
1、 首先創(chuàng)建一個配置類,通過@EnableTransactionManagement開啟事務(wù)管理功能
@Component
@EnableTransactionManagement(proxyTargetClass = false)
@MapperScan(basePackages = {"com.xiangxue.jack.dao"},annotationClass = Repository.class)
public class EnableTransactionManagementBean {
/*
* 以下兩個@Bean的配置都可以設(shè)置數(shù)據(jù)源
* 通過SqlSessionFactoryBean設(shè)置數(shù)據(jù)源
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
/*
* 通過事務(wù)管理平臺的方式設(shè)置數(shù)據(jù)源
*/
@Bean
public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dtm = new DataSourceTransactionManager();
dtm.setDataSource(dataSource);
return dtm;
}
}2、定義數(shù)據(jù)源
@Configuration
@PropertySource("classpath:config/core/core.properties")
public class DataSourceConfiguration {
@Value("${jdbc.driverClassName}")
private String driverClass;
@Value("${jdbc.url:jdbc}")
private String jdbcUrl;
@Value("${jdbc.username}")
private String user;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource comboPooledDataSource() {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
try {
comboPooledDataSource.setDriverClass(driverClass);
comboPooledDataSource.setJdbcUrl(jdbcUrl);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setMinPoolSize(10);
comboPooledDataSource.setMaxPoolSize(100);
comboPooledDataSource.setMaxIdleTime(1800);
comboPooledDataSource.setAcquireIncrement(3);
comboPooledDataSource.setMaxStatements(1000);
comboPooledDataSource.setInitialPoolSize(10);
comboPooledDataSource.setIdleConnectionTestPeriod(60);
comboPooledDataSource.setAcquireRetryAttempts(30);
comboPooledDataSource.setBreakAfterAcquireFailure(false);
comboPooledDataSource.setTestConnectionOnCheckout(false);
comboPooledDataSource.setAcquireRetryDelay(100);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return comboPooledDataSource;
}
}jdbc.driverClassName = org.gjt.mm.mysql.Driver jdbc.url = jdbc:mysql://127.0.0.1:3306/consult jdbc.username = root jdbc.password = 123456
知識點
數(shù)據(jù)源和事務(wù)管理平臺的加載都是在類ProxyTransactionManagementConfiguration中進(jìn)行的。Spring中的事務(wù)就是由 connection對象控制的,所以connection對象是和事務(wù)是綁定的,然后用戶請求過來時又需要數(shù)據(jù)庫連接來執(zhí)行 sql 語句, 所以用戶請求線程又是跟 connection 是綁定的。
開啟事務(wù)注解解析流程
首先看以下@EnableTransactionManagement注解的源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// proxyTargetClass = false 表示是JDK動態(tài)代理支持接口代理。
// true表示是Cglib代理支持子類繼承代理。
boolean proxyTargetClass() default false;
// 事務(wù)通知模式(切面織入方式),默認(rèn)代理模式(同一個類中方法互相調(diào)用攔截器不會生效)
AdviceMode mode() default AdviceMode.PROXY;
// 連接點上有多個通知時,排序,默認(rèn)最低。值越大優(yōu)先級越低。
int order() default Ordered.LOWEST_PRECEDENCE;
}進(jìn)入TransactionManagementConfigurationSelector類
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
/**
* TODO : 導(dǎo)入需要加載的類
* 1、AutoProxyRegistrar: 給容器中注冊一個InfrastructureAdvisorAutoProxyCreator(Spring事務(wù)入口類) 組件;
* 利用后置處理器機(jī)制在對象創(chuàng)建以后,包裝對象,返回一個代理對象(增強(qiáng)器),
* 代理對象執(zhí)行方法利用攔截器鏈進(jìn)行調(diào)用;
*
* 2、ProxyTransactionManagementConfiguration: 就是一個配置類,定義了事務(wù)增強(qiáng)器、攔截器。
*
*/
switch (adviceMode) {
case PROXY:
// 重點看這2個類:
// AutoProxyRegistrar
// ProxyTransactionManagementConfiguration
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}那么這個@EnableTransactionManagement開啟事務(wù)管理配置的注解是如何被調(diào)用的呢?我們回顧一下Spring的初始化核心流程
Spring 初始化核心流程回顧
spring容器初始化的核心方法AbstractApplicationContext#refresh ,
├─refresh Spring 初始化核心流程入口│ ├─prepareRefresh ① 準(zhǔn)備此上下文用于刷新,設(shè)置啟動時間和active標(biāo)志,初始化屬性│ ├─obtainFreshBeanFactory ② 創(chuàng)建 BeanFactory│ ├─prepareBeanFactory ③ 設(shè)置 BeanFactory 的基本屬性│ ├─postProcessBeanFactory ④ 子類處理自定義的BeanFactoryPostProcess│ ├─invokeBeanFactoryPostProcessors ⑤ 開啟事務(wù)管理配置的調(diào)用入口│ ├─registerBeanPostProcessors ⑥ 注冊攔截Bean創(chuàng)建的Bean處理器│ ├─initMessageSource ⑦ 初始化上下文中的資源文件,如國際化文件的處理等│ ├─initApplicationEventMulticaster ⑧ 初始化上下文的事件傳播器│ ├─onRefresh ⑨ 給子類擴(kuò)展初始化其他Bean,springboot 中用來做內(nèi)嵌 tomcat 啟動│ ├─registerListeners ⑩ 在所有bean中查找監(jiān)聽 bean,然后注冊到廣播器中│ ├─finishBeanFactoryInitialization ? 初始化所有的單例Bean、ioc、BeanPostProcessor的執(zhí)行、Aop入口│ └─finishRefresh ? 完成刷新過程,發(fā)布相應(yīng)的事件
進(jìn)入invokeBeanFactoryPostProcessors() 方法
類文件: org.springframework.beans.factory.support.AbstractApplicationContext
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 看這個 invokeBeanFactoryPostProcessors 方法
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}進(jìn)入invokeBeanFactoryPostProcessors() 方法
類文件: org.springframework.beans.factory.support.PostProcessorRegistrationDelegate
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
/** ...... 省略 ...... **/
/**
* 調(diào)用過程
* 在這里典型的 BeanDefinitionRegistryPostProcessor 就是 ConfigurationClassPostProcessor
* 用于進(jìn)行bean定義的加載 比如我們的包掃描,@import等
* @EnableAspectJAutoProxy 注解中的 AspectJAutoProxyRegistrar 類就是通過此方法調(diào)用執(zhí)行
* @EnableTransactionManagement 注解中的 TransactionManagementConfigurationSelector 類就是通過此方法調(diào)用執(zhí)行
*/
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 調(diào)用完之后,馬上clear
currentRegistryProcessors.clear();
}進(jìn)入invokeBeanDefinitionRegistryPostProcessors() 方法
類文件: org.springframework.beans.factory.support.PostProcessorRegistrationDelegate
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
// 重點看這個方法
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}進(jìn)入postProcessBeanDefinitionRegistry() 方法
所在類 org.springframework.context.annotation.ConfigurationClassPostProcessor
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
// 重點看這個方法
processConfigBeanDefinitions(registry);
}知識點
ConfigurationClassPostProcessor類非常重要,此類是對Spring容器中所有的BeanDefinition的新增、修改等操作,也就是說對BeanDefinition的增刪查改都會在ConfigurationClassPostProcessor類中進(jìn)行。同時還支持了@Import、@ImportResource、@ComponetScan、@Configruration等注解的解析工作。
進(jìn)入processConfigBeanDefinitions() 方法,這個時候bean還沒有實例化
類文件: org.springframework.beans.factory.support.ConfigurationClassPostProcessor
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
/** ...... 省略 ...... **/
do {
// 進(jìn)入parse方法
parser.parse(candidates);
parser.validate();
}
while (!candidates.isEmpty());
}接下來的調(diào)用的過程較為繁瑣,此處省略無關(guān)的源碼,按照如下步驟自行跟蹤源碼即可
- 進(jìn)入
parse方法, - 進(jìn)入子
parse方法, - 進(jìn)入
processConfigurationClass方法, - 進(jìn)入
doProcessConfigurationClass方法, - 最后進(jìn)入
processImports方法,
類文件: org.springframework.beans.factory.support.ConfigurationClassParser 到此處,selectImports()方法最終會被ConfigurationClassParser類的processImports()方法調(diào)用執(zhí)行,具體見第ConfigurationClassParser類的第569行,
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
/** ...... 省略 ...... **/
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
// 反射拿到 ImportSelector 接口類的實例化對象 selector
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(
configClass, (DeferredImportSelector) selector);
}
else {
/*
* 然后通過 selector調(diào)用其實現(xiàn)類 AdviceModeImportSelector
* 的selectImports方法,模板中的鉤子方法。最后拿到返回的
* TransactionManagementConfigurationSelector的selectImports
* 方法返回的兩個類:
* 1、AutoProxyRegistrar.class
* 2、ProxyTransactionManagementConfiguration.class
* 繼續(xù)遞歸調(diào)用當(dāng)前的 processImports 方法
*/
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
}開啟事務(wù)的入口類
進(jìn)入selectImports()方法,找到其實現(xiàn)類AdviceModeImportSelector的selectImports方法
類文件: org.springframework.context.annotation.AdviceModeImportSelector
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
// 此方法最終會調(diào)用TransactionManagementConfigurationSelector
// 的 selectImports方法
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}調(diào)回到selectImports方法后,會把AutoProxyRegistrar和ProxyTransactionManagementConfiguration兩個類注冊到Beandefinition中
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
/**
* TODO : 導(dǎo)入需要加載的類
* 1、AutoProxyRegistrar: 給容器中注冊一個InfrastructureAdvisorAutoProxyCreator 組件;
* 利用后置處理器機(jī)制在對象創(chuàng)建以后,包裝對象,返回一個代理對象(增強(qiáng)器),
* 代理對象執(zhí)行方法利用攔截器鏈進(jìn)行調(diào)用;
*
* 2、ProxyTransactionManagementConfiguration: 就是一個配置類,定義了事務(wù)增強(qiáng)器、攔截器。
*
*/
switch (adviceMode) {
case PROXY:
// 重點看這2個類:
// AutoProxyRegistrar
// ProxyTransactionManagementConfiguration
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
}事務(wù)核心類 - AutoProxyRegistrar 源碼
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 循環(huán)遍歷導(dǎo)入類上使用的所有注解(主要處理注解中有 mode和 proxyTargetClass屬性的)
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
// 獲取注解中的 mode 屬性
Object mode = candidate.get("mode");
// 獲取注解中的 proxyTargetClass 屬性
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
// 如果 mode 是代理模式
if (mode == AdviceMode.PROXY) {
// 注冊事務(wù)AOP的入口類 InfrastructureAdvisorAutoProxyCreator,實際上這個AOP入口類起不了作用
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}事務(wù)核心類 - ProxyTransactionManagementConfiguration 源碼
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
//
/**
* TODO : 定義事務(wù)增強(qiáng)器(事務(wù)織入)
*
* 定義了一個 advisor,設(shè)置事務(wù)屬性、設(shè)置事務(wù)攔截器 TransactionInterceptor、設(shè)置順序。
* 核心就是事務(wù)攔截器 TransactionInterceptor。
*/
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
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)
// 主要負(fù)責(zé)解析 @Transactional注解里的屬性資源
// 并包裝為 TransactionAttribute 類型
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// 定義事務(wù)攔截器
public TransactionInterceptor transactionInterceptor() {
// TransactionInterceptor 實現(xiàn)了 MethodInterceptor 接口,
// 在鏈?zhǔn)秸{(diào)用中會自動調(diào)用它的 invoke 方法
TransactionInterceptor interceptor = new TransactionInterceptor();
// 設(shè)置 TransactionAttribute 屬性
interceptor.setTransactionAttributeSource(transactionAttributeSource());
// 如果當(dāng)前事務(wù)管理器不為空,設(shè)置當(dāng)前事務(wù)管理器到攔截器中
// 事務(wù)管理器和數(shù)據(jù)源綁定,此處可以自定義
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}知識點
此處可以參考父類AbstractTransactionManagementConfiguration中的setConfigurers方法,通過重寫TransactionManagementConfigurer的annotationDrivenTransactionManager方法來自定義一個事務(wù)管理器。
@Component
public class TransactionManagementConfigurerBean implements TransactionManagementConfigurer {
@Autowired
private DataSource dataSource;
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
DataSourceTransactionManager dtm = new DataSourceTransactionManager();
dtm.setDataSource(dataSource);
return dtm;
}
}到此為止,Spring中@EnableTransactionManagement注解的內(nèi)部注冊解析的準(zhǔn)備工作完成。
事務(wù)攔截器
TransactionInterceptor
Spring聲明式事物是基于AOP實現(xiàn)的,如果目標(biāo)方法存在事物則會對目標(biāo)對象進(jìn)行增強(qiáng)代理(JDK/Cglib)。而TransactionInterceptor則是事物體系中的增強(qiáng)器(Advise),它實現(xiàn)了MethodInterceptor接口,TransactionInterceptor會被封裝在使用了事務(wù)注解@Transactional的bean組件外面形成該組件的代理對象,當(dāng)調(diào)用相應(yīng)使用事務(wù)注解的方法時,TransactionInterceptor的invoke方法攔截器邏輯會被調(diào)用執(zhí)行,從而完成相應(yīng)的事務(wù)管理,包括:創(chuàng)建、提交和回滾等底層操作。
Spring 事務(wù)攔截處理流程
spring事務(wù)攔截器解析流程TransactionInterceptor#invoke ,
├─invoke Spring 事務(wù)攔截器入口├─invokeWithinTransaction 調(diào)用Spring內(nèi)部事務(wù)│ ├─getTransactionAttributeSource ① 通過事務(wù)屬性源讀取事務(wù)的屬性配置│ ├─getTransactionAttribute ② 獲取該方法的事務(wù)屬性(傳播機(jī)制、隔離級別)│ ├─determineTransactionManager ③ 查找容器中的PlatformTransactionManager,用于管理事務(wù)│ ├─methodIdentification ④ 獲取被代理的類方法名稱│ ├─createTransactionIfNecessary ⑤ 創(chuàng)建事務(wù)并保存到TransactionInfo 聲明式事務(wù)│ ├─proceedWithInvocation ⑥ 火炬?zhèn)鬟f方法,攔截器鏈調(diào)用處理│ ├─completeTransactionAfterThrowing ⑦ 執(zhí)行業(yè)務(wù)報錯,回滾事務(wù)│ ├─cleanupTransactionInfo ⑧ 清空當(dāng)前事務(wù)信息,重置為老的│ ├─commitTransactionAfterReturning ⑨ 返回結(jié)果之前提交事務(wù)│ ├─execute ① 執(zhí)行實現(xiàn)TransactionCallback接口的doInTransaction回調(diào)方法 編程式事務(wù)│ │ ├─prepareTransactionInfo ② 準(zhǔn)備事務(wù)信息│ │ │ ├─new TransactionInfo ③ 創(chuàng)建事務(wù)信息對象│ │ │ ├─newTransactionStatus ④ 為事務(wù)信息對象設(shè)置事務(wù)狀態(tài)│ │ │ └─bindToThread ⑤ 把創(chuàng)建的事務(wù)信息對象和線程綁定到TreadLocal│ │ ├─proceedWithInvocation ⑥ 火炬?zhèn)鬟f方法, 攔截器鏈調(diào)用處理│ │ ├─rollbackOn ⑦ 事務(wù)是否滿足對異常進(jìn)行回滾處理條件│ │ └─cleanupTransactionInfo ⑧ 初始化所有的單例Bean、ioc、BeanPostProcessor的執(zhí)行、Aop入口
進(jìn)入invoke 方法,
類文件: org.springframework.transaction.interceptor.TransactionInterceptor
/**
* TODO : 事務(wù)攔截器的攔截方法
* 事務(wù)攔截器TransactionInterceptor回調(diào)方法invoke通過調(diào)用TransactionAspectSupport事務(wù)切面支持類中的
* createTransactionIfNecessary和prepareTransactionInfo方法創(chuàng)建事務(wù)對象
*/
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.
// 通過 AOP獲取事務(wù)的目標(biāo)類
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
// 核心方法,調(diào)用內(nèi)部事務(wù)處理,實際調(diào)用父類 TransactionAspectSupport的 invokeWithinTransaction方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}進(jìn)入invokeWithinTransaction 方法,父類中實現(xiàn)
類文件: org.springframework.transaction.interceptor.TransactionAspectSupport
/**
* TODO : 調(diào)用內(nèi)部事務(wù)
*/
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 通過事務(wù)屬性源 TransactionAttributeSource讀取事務(wù)的屬性配置(名稱匹配)
TransactionAttributeSource tas = getTransactionAttributeSource();
// 獲取對應(yīng)事務(wù)屬性.如果事務(wù)屬性為空(則目標(biāo)方法不存在事務(wù))
// 事務(wù)屬性源 NameMatchTransactionAttributeSource 的方法
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 根據(jù)事務(wù)的屬性獲取 beanFactory 中的 PlatformTransactionManager (spring事務(wù)管理器的頂級接口),
// 獲取 Spring事務(wù)管理IoC容器配置的事務(wù)處理器
// 一般常用實現(xiàn)是 DataSourceTransactiuonManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 目標(biāo)方法唯一標(biāo)識(類.方法,如service.ServiceImpl.add)
// 獲取目標(biāo)類指定方法的事務(wù)連接點
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
/*
* 區(qū)分不同類型的 PlatformTransactionManager事務(wù)處理器,不同類型的事務(wù)處理器調(diào)用方式不同。對
* CallbackPreferringPlatformTransactionManager,需要回調(diào)函數(shù)來實現(xiàn)事務(wù)的創(chuàng)建和提交,對非
* CallbackPreferringPlatformTransactionManager來說,則不需要使用回調(diào)函數(shù)來實現(xiàn)事務(wù)處理。
*/
// 如果txAttr為空或者tm 屬于非CallbackPreferringPlatformTransactionManager類型的事務(wù)處理器
// 聲明式事務(wù)的操作
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 使用 getTransaction 和 提交/回滾 調(diào)用的標(biāo)準(zhǔn)事務(wù)劃分。
// 創(chuàng)建事務(wù),將當(dāng)前事務(wù)狀態(tài)和信息保存到TransactionInfo對象中,重要
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 這里就是一個環(huán)繞增強(qiáng),在這個proceed前后可以自己定義增強(qiáng)實現(xiàn)。
// 回調(diào)方法執(zhí)行,執(zhí)行目標(biāo)方法(原有的業(yè)務(wù)邏輯)
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 根據(jù)事務(wù)定義的,該異常需要回滾就回滾,否則提交事務(wù)
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 清空當(dāng)前事務(wù)信息,重置為老的
cleanupTransactionInfo(txInfo);
}
// 返回結(jié)果之前提交事務(wù)
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 編程式事務(wù)
// CallbackPreferringPlatformTransactionManager類型的事務(wù)處理器
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
// 執(zhí)行實現(xiàn)T ransactionCallback 接口的 doInTransaction 回調(diào)方法
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
// 攔截器鏈調(diào)用處理,使得最后目標(biāo)對象的方法得到調(diào)用
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 如果事務(wù)滿足對異常進(jìn)行回滾處理條件
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
// 如果異常是運行時異常,則事務(wù)回滾處理
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
//如果不是運行時異常,則提交處理
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
// 提交處理
throwableHolder.throwable = ex;
return null;
}
}
//清除當(dāng)前線程綁定的事務(wù)信息
finally {
cleanupTransactionInfo(txInfo);
}
}); // 到這里都是execute方法
// Check result state: It might indicate a Throwable to rethrow.
// 如果是ThrowableHolder類型的異常,則轉(zhuǎn)換為Throwable拋出,上拋異常
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
// 否則異常不做處理直接拋出
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}進(jìn)入getTransactionAttribute 方法,父類中實現(xiàn)
類文件: org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 首先看是否存在緩存值
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// 如果緩存的是一個無事務(wù)對象,直接返回 null
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
// 緩存中不存在
else {
// 重新計算 TransactionAttribute 屬性,根據(jù)方法和類的類型獲取事務(wù)信息
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 存到緩存中
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
// 將事務(wù)對象屬性放到緩存中,緩存的key與類的類型和方法相關(guān)
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}進(jìn)入computeTransactionAttribute 方法,父類中實現(xiàn)
類文件: org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 如果被代理方法非public類型,則直接返回空,Spring事務(wù)不支持非public類型方法
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// 方法可能在接口上,但是我們需要目標(biāo)類的屬性。
// 如果目標(biāo)類為空,則方法將保持不變。
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
// 解析方法上的 @Transactional 屬性
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
// 如果方法上沒有事務(wù)屬性,就從類上來獲取
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}知識點
被代理方法是否是public類型,就是在computeTransactionAttribute這個方法中進(jìn)行校驗的,Spring中的事務(wù)只對public類型的方法起作用,非public類型事務(wù)失效。
@Transactional注解的解析
- 進(jìn)入
findTransactionAttribute方法, - 進(jìn)入
determineTransactionAttribute方法, - 進(jìn)入
parseTransactionAnnotation方法,
類文件: org.springframework.transaction.annotation.SpringTransactionAnnotationParser
/**
* TODO : 解析事務(wù)注解中的屬性
*/
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 獲取事務(wù)傳播屬性
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
// 獲取事務(wù)隔離等級
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
// 獲取事務(wù)獲取事務(wù)超時時間
rbta.setTimeout(attributes.getNumber("timeout").intValue());
// 獲取事務(wù)是否只讀
rbta.setReadOnly(attributes.getBoolean("readOnly"));
// 獲取事務(wù)事務(wù)管理器 bean的名稱
rbta.setQualifier(attributes.getString("value"));
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
// 獲取事務(wù)回滾相關(guān)配置
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}到此為止,@Transactional注解的加載工作也完成,注解的屬性值已近被加載到spring容器中了,接下來開始具體的事務(wù)操作過程。
事務(wù)的實現(xiàn)過程
創(chuàng)建事務(wù)之前的準(zhǔn)備工作已經(jīng)完成了,那么具體事務(wù)是如何創(chuàng)建實現(xiàn)的呢?
回到invokeWithinTransaction方法,
進(jìn)入createTransactionIfNecessary 方法,
類文件: org.springframework.transaction.interceptor.TransactionAspectSupport
/**
* TODO : 根據(jù)給定的事務(wù)屬性創(chuàng)建事務(wù)對象
*/
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 如果沒有指定名稱,則應(yīng)用方法標(biāo)識作為事務(wù)名稱。
// 讀取事務(wù)方法調(diào)用的事務(wù)配置屬性
if (txAttr != null && txAttr.getName() == null) {
// 如果事務(wù)名稱為 null,則使用方法的名稱(事務(wù)連接點標(biāo)識)作為事務(wù)名稱,
// 調(diào)用一個實現(xiàn) DelegatingTransactionAttribute 接口的匿名內(nèi)部類
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
// 使用方法名稱作為事務(wù)名稱
public String getName() {
return joinpointIdentification;
}
};
}
// 事務(wù)狀態(tài)封裝了事務(wù)執(zhí)行的狀態(tài)信息
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 事務(wù)處理器創(chuàng)建事務(wù),并且返回當(dāng)前事務(wù)的狀態(tài)信息
// 核心方法,真正底層創(chuàng)建事務(wù)對象的方法
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 準(zhǔn)備事務(wù)信息,事務(wù)信息 TransactionInfo 封裝了事務(wù)配置和狀態(tài)信息
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}進(jìn)入getTransaction 方法,
類文件: org.springframework.transaction.support.AbstractPlatformTransactionManager
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// doGetTransaction()方法是抽象方法,具體的實現(xiàn)由具體的事務(wù)處理器提供
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
// 如果沒有配置事務(wù)屬性,則使用默認(rèn)的事務(wù)屬性
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 檢查當(dāng)前線程是否存在事務(wù),如果已存在事務(wù),那么需要根據(jù)在事務(wù)屬性中定義的事務(wù)傳播屬性來處理事務(wù)的產(chǎn)生(檢查傳播行為)
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// 處理已存在的事務(wù)的情況
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
// 檢查事務(wù)屬性中timeout超時屬性設(shè)置是否合理
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
// 對事務(wù)屬性中配置的事務(wù)傳播特性處理
// 如果當(dāng)前獲取不到存在的事務(wù),且事務(wù)傳播特性配置的是 mandatory,當(dāng)前沒有事務(wù)存在,拋出異常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 獲取不到存在的事務(wù),并且事務(wù)傳播屬性是 REQUIRED、REQUIRES_NEW、NESTED
// 則執(zhí)行事務(wù)掛起,新建事務(wù)。
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 掛起當(dāng)前事務(wù)
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
// 不激活和當(dāng)前線程綁定的事務(wù),因為事務(wù)傳播特性配置要求創(chuàng)建新的事務(wù)
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 創(chuàng)建一個新的事務(wù)狀態(tài)
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 核心方法:創(chuàng)建事務(wù)的調(diào)用,具體實現(xiàn)由具體的事務(wù)處理器提供。
// 設(shè)置事務(wù)隔離級別(spring默認(rèn)的事務(wù)隔離級別是跟JDBC相同的,即默認(rèn)情況Spring不設(shè)置事務(wù)隔離級別);
doBegin(transaction, definition);
// 初始化和同步事務(wù)狀態(tài)
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
// 創(chuàng)建空事務(wù),針對 supported 類型的事務(wù)傳播特性,激活和當(dāng)前線程綁定的事務(wù)
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 準(zhǔn)備事務(wù)狀態(tài)
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}知識點
抽象事務(wù)管理器AbstractPlatformTransactionManager提供了創(chuàng)建事務(wù)的模板,這個模板會被具體的事 務(wù)處理器所使用,抽象事務(wù)管理器根據(jù)事務(wù)屬性配置和當(dāng)前線程綁定信息對事務(wù)是否需要創(chuàng)建以及如何創(chuàng)建進(jìn)行一 些通用的處理,然后把事務(wù)創(chuàng)建的底層細(xì)節(jié)交給具體的事務(wù)處理器實現(xiàn)。
進(jìn)入doGetTransaction 方法,由jdbc包下的數(shù)據(jù)源類實現(xiàn)
類文件: org.springframework.jdbc.datasource.DataSourceTransactionManager
protected Object doGetTransaction() {
// 管理 connection對象,創(chuàng)建回滾點,按照回滾點回滾,釋放回滾點
// DataSourceTransactionObject 就是真正的事務(wù)對象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// DataSourceTransactionManager 默認(rèn)是允許嵌套事務(wù)的
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// obtainDataSource() 獲取數(shù)據(jù)源對象,其實就是數(shù)據(jù)庫連接對象
// ConnectionHolder 持有了 Connection,并對 Connection進(jìn)行了包裝
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}進(jìn)入getResource方法,
類文件: org.springframework.transaction.support.TransactionSynchronizationManager
public static Object getResource(Object key) {
// 查看數(shù)據(jù)源連接池有沒有擴(kuò)展,一般沒有
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}進(jìn)入doGetResource方法,
類文件: org.springframework.transaction.support.TransactionSynchronizationManager
private static Object doGetResource(Object actualKey) {
// 事務(wù)默認(rèn)傳播屬性會共用同一個連接,因此會去 ThreadLocal 中獲取連接,如果存在就直接返回
// map對應(yīng)了當(dāng)前數(shù)據(jù)源對象和 當(dāng)前連接的綁定關(guān)系
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}執(zhí)行到doGetResource,也就說明了,事務(wù)的執(zhí)行默認(rèn)使用了同一個數(shù)據(jù)庫連接。
doGetTransaction 方法執(zhí)行完返回了事務(wù)對象,返回到getTransaction方法中
進(jìn)入doBegin方法
類文件: org.springframework.jdbc.datasource.DataSourceTransactionManager
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 如果沒有數(shù)據(jù)庫連接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 從連接池里面獲取連接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 把連接包裝成 ConnectionHolder,然后設(shè)置到事務(wù)對象中
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 從數(shù)據(jù)庫連接中獲取隔離級別,Mysql默認(rèn)隔離級別是 可重復(fù)讀
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
// 關(guān)閉連接的自動提交,其實這步就是開啟了事務(wù)
con.setAutoCommit(false);
}
// 設(shè)置只讀事務(wù) 從這一點設(shè)置的時間點開始(時間點a)到這個事務(wù)結(jié)束的過程中,
// 其他事務(wù)所提交的數(shù)據(jù),該事務(wù)將看不見!
// 設(shè)置只讀事務(wù)就是告訴數(shù)據(jù)庫,我這個事務(wù)內(nèi)沒有新增,修改,刪除操作
// 只有查詢操作,不需要數(shù)據(jù)庫鎖等操作,減少數(shù)據(jù)庫壓力
prepareTransactionalConnection(con, definition);
// 自己提交關(guān)閉了,就說明已經(jīng)開啟事務(wù)了,事務(wù)是活動的
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
// 如果是新創(chuàng)建的事務(wù),則建立當(dāng)前線程和數(shù)據(jù)庫連接的關(guān)系
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}doBegin方法中的 con.setAutoCommit(false)執(zhí)行完,正式開啟了Spring 事務(wù)管理功能。
事務(wù)問題匯總
問題一
AutoProxyRegistrar是AOP的入口類,之前@EnableAspectJAutoProxy也會通過AutoProxyRegistrar生成一個AOP的入口類,那么AOP的入口類會有兩個嗎?
參考答案
不會,Spring AOP創(chuàng)建的入口類名字默認(rèn)都叫org.springframework.aop.config.internalAutoProxyCreator,并且優(yōu)先級設(shè)置在AopConfigUtils類中:
static {
// 事務(wù)代理 入口類優(yōu) 先級最低
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
// XML代理 入口類 優(yōu)先級其次
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
// AspectJ代理 入口類 優(yōu)先級最高
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}由此可見,AspectJ的入口類AnnotationAwareAspectJAutoProxyCreator優(yōu)先級最高,也就是說如果設(shè)置了切面,那么入口類只會有AnnotationAwareAspectJAutoProxyCreator會起作用。
問題二
兩個方法上都使用了@Transactional默認(rèn)傳播屬性,內(nèi)部是如何保證使用了同一個連接的?
參考答案
事務(wù)默認(rèn)傳播屬性會共用同一個連接,內(nèi)部是通過ThreadLocal來保證連接的重復(fù)可用。默認(rèn)第一次肯定不會從Map中拿到連接,直接返回null,只有第二次進(jìn)來get()的值才不會為空。
private static Object doGetResource(Object actualKey) {
// 事務(wù)默認(rèn)傳播屬性會共用同一個連接,因此會去 ThreadLocal 中獲取連接,
// 如果存在就直接返回,否則創(chuàng)建新的連接
// Map保存了當(dāng)前數(shù)據(jù)源對象 和 當(dāng)前連接的綁定關(guān)系
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限的示例代碼
在我們?nèi)粘i_發(fā)過程中,通常會涉及到數(shù)據(jù)權(quán)限問題,本文主要介紹了Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
java.sql.SQLException異常原因排查與解決
在日常開發(fā)中,大家應(yīng)該或多或少都遇到SQL 在本地跑得好好的,一放到服務(wù)里執(zhí)行就報 java.sql.SQLException,本文將結(jié)合一個小 Demo,帶大家看一下 SQLException 的常見原因,以及如何一步步排查2025-09-09
java打包成jar并執(zhí)行jar包中指定的main方法
這篇文章主要介紹了如何將java打包成可執(zhí)行的jar,并執(zhí)行jar包中指定的main方法的相關(guān)資料,文中給出了詳細(xì)的示例代碼,對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-03-03
使用java + selenium + OpenCV破解騰訊防水墻滑動驗證碼功能
這篇文章主要介紹了使用java + selenium + OpenCV破解騰訊防水墻滑動驗證碼,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11

