0

I am following this link for understanding hexagonal architecture with spring boot. The infrastructure section contains the configuration for the service bean and the repository is passed as a parameter as a below method.

Configuration

@Configuration
@ComponentScan(basePackageClasses = HexagonalApplication.class)
public class BeanConfiguration {

      @Bean
      BankAccountService bankAccountService(BankAccountRepository repository) {
          return new BankAccountService(repository, repository);
      }
}

I am not using JPA instead using Spring JDBC for interacting to DB. Linked tutorial is using JPA.

Lets say I have different database implementations i.e.. postgresql(BankAccountRepository) and db2(BankAccountDB2Rep) . I want to change the beans without touching the code. something like with yml configuration or something which I can maintain separately instead of touching the code.

BankAccountRepository.java

@Component
public class BankAccountRepository implements LoadAccountPort, SaveAccountPort {

      private SpringDataBankAccountRepository repository;

      // Constructor

      @Override
      public Optional<BankAccount> load(Long id) {
          return repository.findById(id);
      }

      @Override
      public void save(BankAccount bankAccount) {
          repository.save(bankAccount);
      }
}

How can I achieve the same in spring boot? Any help is appreciated..

Sai Sarath C P
  • 1,454
  • 2
  • 9
  • 26
  • Note that your example isn't a great once, since you should generally be using JPA which will abstract that away for you anyway, but you should be looking at the docs for Spring Boot auto-configuration. Depending on how your application is set up, `@ConditionalOnClass(org.h2.Driver.class)` might be appropriate. – chrylis -cautiouslyoptimistic- Jun 01 '21 at 02:52
  • @chrylis-cautiouslyoptimistic- I don't want to use JPA for several other reasons, there will be several db related implementations like different repositories. to decouple the DB layer implementation, I want to inject beans on application startup. I am seeing if I can control that using a configuration file – Sai Sarath C P Jun 01 '21 at 03:55
  • Is it either Postgres or DB2 or do both have to be available? In the first case just use a conditional rule to instantiate either one of the repositories. Also you seem to already be using JPA as you have a `SpringDataBankAccountRepository` which looks like Spring Data JPA to me and that, with proper configuration, will just toggle the dialect to use for the underlying DB. – M. Deinum Jun 01 '21 at 05:16
  • @M.Deinum My bad, Although the example contains the JPA, I am using Spring JDBC and want to implement repository implementation for each and every database. Like MariaDB has no routines, whereas MySQ/PostgreSQL I can use routines. – Sai Sarath C P Jun 01 '21 at 08:08
  • 1
    If it is either one, just use conditional beans. – M. Deinum Jun 01 '21 at 08:12
  • I haven't read it but this should work @M.Deinum . Thanks for the input – Sai Sarath C P Jun 01 '21 at 12:53

2 Answers2

0

You can refer to Spring Boot Configure and Use Two DataSources for creating multiple datasources and do something like following.

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
  entityManagerFactoryRef = "entityManagerFactory",
  transactionManagerRef = "transactionManager",
  basePackages = {
   "com.example"
  }
)
public class JPAConfig {

    @Primary
    @Bean(name = "postgresDataSource")
    @ConfigurationProperties(prefix = "postgres.datasource")
    public DataSource postgresDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "db2DataSource")
    @ConfigurationProperties(prefix = "db2.datasource")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
    EntityManagerFactoryBuilder builder,
    @Qualifier("postgresDataSource") DataSource postgresdataSource,
    @Qualifier("db2DataSource") DataSource db2dataSource,
    @Value("${useDb2}") Boolean useDb2
    ) {
        return builder
        .dataSource(useDb2? db2dataSource : postgresdataSource)
        .packages("com.example")
        .persistenceUnit("db1")
        .build();
    }

    @Primary
    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(
    @Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory
    ) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}
0

As mentioned by @M.Deinum in comments, the issue can be resolved by using the spring conditional beans, as below

@Configuration
@ConditionalOnProperty(
    value="module.enabled", 
    havingValue = "true", 
    matchIfMissing = true)
class CrossCuttingConcernModule {
  ...
}

More information can be found here

Sai Sarath C P
  • 1,454
  • 2
  • 9
  • 26