简体   繁体   中英

Dynamic Bean configuration & loading in spring boot

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 ie. 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..

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);
    }
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM