TransactionManager Spring 启动的动态选择

Dynamic Selection of TransactionManager Spring Boot

我正在将我现有的 Spring 应用程序转换为 Spring 启动应用程序。在我现有的应用程序中,我们需要连接到多个数据库,我们通过定义多个数据源并根据条件获取相应的 bean 来实现这一点。还使用 TransactionInterceptor 的自定义实现选择了事务管理器。

@Override
public TransactionAttributeSource getTransactionAttributeSource() {
    final TransactionAttributeSource origTxAttrSource = super.getTransactionAttributeSource();
    return new TransactionAttributeSource() {

        @Override
        public TransactionAttribute getTransactionAttribute(final Method method, final Class<?> targetClass) {
            TransactionAttribute txAttr = origTxAttrSource.getTransactionAttribute(method, targetClass);
            String database = (String) ThreadContext.get("database");
            if (database != null && StringUtils.isNotBlank(database)) {
                if (txAttr instanceof DefaultTransactionAttribute) {
                    ((DefaultTransactionAttribute) txAttr).setQualifier("txManager" + database);
                }
            }
            return txAttr;
        }
    };
}

通过 BeanFactoryPostProcessor 我们包含了这个拦截器

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
         String[] names = beanFactory.getBeanNamesForType(TransactionInterceptor.class);
        for (String name : names) {
            BeanDefinition bd = beanFactory.getBeanDefinition(name);
            bd.setBeanClassName(MyTransactionInterceptor.class.getName());

        }
}

这在 Spring 4.X 中运行得非常好。

既然我们正在转向 Spring 引导,我正在尝试转换相同的方法。我可以看到正在调用 bean 工厂,但我没有发现自定义拦截器发生调用 class。这导致我的 @Transactional 失败,因为有不止一个符合条件的 bean。

关于 Spring 引导配置,我是否遗漏了什么?

(这种动态事务管理的方法是通过参考博客http://blog.tirasa.net/dynamic-springs--at-transactional.html

最后的答案是将工厂 类 和工厂 bean 名称设置为 null,这导致事务拦截器被调用。我还没有弄清楚这如何影响拦截器调用以及这些字段中的值(它们指向 ProxyTransaction 类 因为 transactionInterceptor bean 是由它创建的)。

最终代码的形式为 -

事务拦截器Class

@Component
public class TransactionInterceptorReplacer implements BeanFactoryPostProcessor {

@Override
    public void postProcessBeanFactory(final ConfigurableListableBeanFactory factory) throws BeansException {
        String[] names = factory.getBeanNamesForType(TransactionInterceptor.class);
        for (String name : names) {
            BeanDefinition bd = factory.getBeanDefinition(name);
            bd.setBeanClassName(MyTransactionInterceptor.class.getName());
            bd.setFactoryBeanName(null);
            bd.setFactoryMethodName(null);
       }
   }
}