Search code examples
springspring-jdbcspring-transactions

Spring Disable @Transactional from Configuration java file


I have a codebase which is using in two different applications. Some of the spring service classes has annotation @Transactional. On server start I would like to disable @Transactional based on some configuration.

The below is my configuration Class.

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:application.properties")

public class WebAppConfig {

    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";

    @Resource
    private Environment env;
    
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
        dataSource.setUrl(url);
        dataSource.setUsername(userId);
        dataSource.setPassword(password);

        return dataSource;
    }
    @Bean
    public PlatformTransactionManager txManager() {
         DefaultTransactionDefinition def = new DefaultTransactionDefinition();
         def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
            if(appName.equqls("ABC")) {
                def.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER);
                }else {
                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
                }
         CustomDataSourceTransactionManager txM=new CustomDataSourceTransactionManager(def);
         txM.setDataSource(dataSource());
    return txM;
    }
    

    @Bean
    public JdbcTemplate jdbcTemplate() {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource());
        return jdbcTemplate;
    }
    
}

I tried overriding methods in DataSourceTransactionManager to make the functionality, but still it is trying to commit/rollback the transaction at end of transaction. Since there is no database connection available it is throwing exception.

If I keep @Transactional(propagation=Propagation.NEVER), everything works perfectly, but I cannot modify it as another app is using the same code base and it is necessary in that case.

I would like to know if there is a way to make transaction fully disable from configuration without modifying @Transactional annotation.


Solution

  • I'm not sure if it would work but you can try to implement custom TransactionInterceptor and override its method that wraps invocation into a transaction, by removing that transactional stuff. Something like this:

    public class NoOpTransactionInterceptor extends TransactionInterceptor {
    
        @Override
        protected Object invokeWithinTransaction(
            Method method, 
            Class<?> targetClass, 
            InvocationCallback invocation
        ) throws Throwable {
            // Simply invoke the original unwrapped code
            return invocation.proceedWithInvocation();
        }
    }
    

    Then you declare a conditional bean in one of @Configuration classes

    // assuming this property is stored in Spring application properties file
    @ConditionalOnProperty(name = "turnOffTransactions", havingValue = "true")) 
    @Bean   
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor(
             /* default bean would be injected here */
             TransactionAttributeSource transactionAttributeSource
    ) {
        TransactionInterceptor interceptor = new NoOpTransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        return interceptor;
    }
    

    Probably you gonna need additional configurations, I can't verify that right now