0

I am studying for the Spring Core certification and I have the followind doubt with an exercice related to the beans configuration using the Java configuration way.

So I have the following RewardsConfig class that configure my beans (this class is into the application folder src/main/java):

package config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import rewards.RewardNetwork;
import rewards.internal.RewardNetworkImpl;
import rewards.internal.account.AccountRepository;
import rewards.internal.account.JdbcAccountRepository;
import rewards.internal.restaurant.JdbcRestaurantRepository;
import rewards.internal.restaurant.RestaurantRepository;
import rewards.internal.reward.JdbcRewardRepository;
import rewards.internal.reward.RewardRepository;

@Configuration
public class RewardsConfig {

    @Autowired
    DataSource dataSource;

    @Bean
    public RewardNetwork rewardNetwork(){
        return new RewardNetworkImpl(accountRepository(), restaurantRepository(), rewardRepository());
    }

    @Bean
    public AccountRepository accountRepository(){
        JdbcAccountRepository repository = new JdbcAccountRepository();
        repository.setDataSource(dataSource);
        return repository;
    }

    @Bean
    public RestaurantRepository restaurantRepository(){
        JdbcRestaurantRepository repository = new JdbcRestaurantRepository();
        repository.setDataSource(dataSource);
        return repository;
    }

    @Bean
    public RewardRepository rewardRepository(){
        JdbcRewardRepository repository = new JdbcRewardRepository();
        repository.setDataSource(dataSource);
        return repository;
    }

}

As you can see I declare 4 methods that are used to create 4 beans and that specify the dependency that occurs among these beans.

So I have a RewardNetwork bean that is implemented by RewardNetworkImpl class that depends from the following 3 beans: AccountRepository, RestaurantRepository and RewardRepository.

Is it the correct interpretation of the Java configuration is Spring?

Can I say for example that RewardNetwork is the declared bean and that RewardNetworkImpl its the current implementation of this bean?

All the 3beans (AccountRepository, RestaurantRepository and RewardRepository) depends by another bean dataSource that, as you can see in the previous code snippet, is declared as @Autowired:

@Autowired
DataSource dataSource;

This bean is not declared in this configuration class because it changes according to the environment (test, developt, production).

So, in my case it is declared into the unit test folder src/test/java:

package rewards;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;

@Configuration
public class TestInfrastructureConfig {

    /**
     * Creates an in-memory "rewards" database populated 
     * with test data for fast testing
     */
    @Bean
    public DataSource dataSource(){
        return
            (new EmbeddedDatabaseBuilder())
            .addScript("classpath:rewards/testdb/schema.sql")
            .addScript("classpath:rewards/testdb/test-data.sql")
            .build();
    }   
}

So the dataSource bean define a datasource that is valid only for the test environment (used when I perform a unit test).

Now my doubt is: I have 2 different configuration classes and the dataSource bean is not definied into the RewardsConfig configuration class that contains the 3 beans that use it. Why I can't not use the @Import annotation to use it into RewardsConfig?

Something like it:

@Import(TestInfrastructureConfig.class)

How it work exactly?

Tnx

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
AndreaNobili
  • 40,955
  • 107
  • 324
  • 596

1 Answers1

1

You don't have to import beans to make them available for autowiring. @Import is used to add extra configuration classes.

You really don't want to hard-import a test configuration class, because then your production code is referring to test-only code (and, in this case, always activating it). Instead, think of your configuration class more like an abstract class: declare autowired beans, but don't worry about how they get there. The downstream (runtime) configuration will supply them, and you don't need to know how. Maybe you're supplying an in-memory H2 for testing and using Spring Cloud Connectors for actual runs, doesn't matter.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
  • mm ok now I have understand that using Import annotation I don't have to import beans. In this case the TestInfrastructureConfig is only for the test environment that I will not have in production environment. Do you mean that I can use Import annotation to handle these situation? Now that I am in a test environment it load the TestInfrastructureConfig but when I will be in production environment I will have not TestInfrastructureConfig but instead it I will have ProductionInfrastructureConfig and this class will automatically used? It this the meaning of the Autowired annotation choise? Tnx – AndreaNobili Nov 12 '14 at 10:40
  • 1
    Autowired means that Spring will find some matching bean somewhere. The class using it, whether a configuration class or other service bean, doesn't need to know where Spring gets it; it doesn't have to provide all its own dependencies. Your test case will need to include some other, unrelated source that provides a `DataSource`. – chrylis -cautiouslyoptimistic- Nov 12 '14 at 12:28