定义一个自己的事务管理器
@Bean
public DataSourceTransactionManager myTransactionManager(Environment environment, DataSource dataSource) {
return environment.getProperty("spring.dao.exceptiontranslation.enabled", Boolean.class, Boolean.TRUE)
? new JdbcTransactionManager(dataSource) : new DataSourceTransactionManager(dataSource);
}
默认的事务管理器
public class DataSourceTransactionManagerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(DataSource.class)
static class JdbcTransactionManagerConfiguration {
@Bean
@ConditionalOnMissingBean(TransactionManager.class)
DataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
transactionManagerCustomizers
.ifAvailable((customizers) -> customizers.customize((TransactionManager) transactionManager));
return transactionManager;
}
private DataSourceTransactionManager createTransactionManager(Environment environment, DataSource dataSource) {
return environment.getProperty("spring.dao.exceptiontranslation.enabled", Boolean.class, Boolean.TRUE)
? new JdbcTransactionManager(dataSource) : new DataSourceTransactionManager(dataSource);
}
}
}
注意这里使用一个@ConditionalOnMissingBean(TransactionManager.class)
我之前一直理解是容器没有这个TransactionManager的bean就会获取, 但是其实不是这样
说清楚我的疑问
我在myTransactionManager打上断点, 并将@Transactional的注解使用"transactionManager"作为bean名称, 按理说我此时获取, 此时容器应该还没有myTransactionManager的bean(因为断点没有执行), 所以应该可以正常获取到transactionManager的bean(因为容器中没有TransactionManager.class的bean), @ConditionalOnMissingBean(TransactionManager.class)的条件应该可以命中, 执行创建默认bean的逻辑, 但是却报错了
为什么不去创建默认bean
阅读源码发现本质
断点打在这里
org.springframework.beans.factory.BeanFactoryUtils#beanNamesForTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<?>)
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
String[] result = lbf.getBeanNamesForType(type); // 这里打断点
if (lbf instanceof HierarchicalBeanFactory hbf) {
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory pbf) {
String[] parentResult = beanNamesForTypeIncludingAncestors(pbf, type);
result = mergeNamesWithParent(result, parentResult, hbf);
}
}
return result;
}
接着到org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeanNamesForType(java.lang.Class<?>, boolean, boolean)
@Override
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
接着进入
doGetBeanNamesForType方法
你就会发现, 判断bean存不存在其实不是从bean容器中获取的, 是从beanDefinition获取, 我们知道spring是先获取了所有的beanDefinition然后实例化bean的, 所以当要实例化默认bean时候,发现已经有一个bean被定义了, 此时@ConditionalOnMissingBean(TransactionManager.class)不成立, 所以直接获取bean失败, 抛出了异常
结论
@ConditionalOnMissingBean(TransactionManager.class)的注解不看spring容器中有没有bean, 而是看beanDefinition有没有定义bean