为什么自定义的事务管理器还没有创建, 获取默认事务管理器还是报错(获取不到)

文章解释了Spring中的`@ConditionalOnMissingBean(TransactionManager.class)`注解实际上并不检查容器中是否存在该类型的bean,而是检查beanDefinition是否已定义。当试图在beanDefinition中找到未定义的bean时,它会创建默认bean,否则抛出异常。
摘要由CSDN通过智能技术生成

定义一个自己的事务管理器

    @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

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岁月玲珑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值