What happens in Spring if I use the @ActiveProfiles annotation on a configuration class instead use it on the class that defines my beans?

16,846

If you look at the JavaDoc of ActiveProfiles annotation, it contains this text:

ActiveProfiles is a class-level annotation that is used to declare which active bean definition profiles should be used when loading an ApplicationContext for test classes.

Meaning it is only supposed to be used to declare active Spring profiles for test classes. So If put it on a Configuration class it should have no effect.

And as for the @Profile annotation, it can be used on both method and class level. If you use it on method annotated with @Bean in configuration class, only that bean will belong to the profile. If you use it on configuration class, it will be applied to all the beans within the configuration class, if you use it on @Component class, the profile will be applied to the bean represented by that class.

@Profile annotation JavaDoc provides more detailed explanation of these rules.

Why I have to use the @Profile annotation on a **configuration class* instead annotate directly my beans?

Well if all beans in given configuration class should be active only for certain profile(s) then it makes sense to declare that globally on the configuration class to avoid having to individually specify the profile on all beans. But If you were to annotate all indiviudal beans it would work as well.

Share:
16,846
AndreaNobili
Author by

AndreaNobili

Updated on June 05, 2022

Comments

  • AndreaNobili
    AndreaNobili almost 2 years

    I am studying for the Spring Core certification and I have some doubts related to the use of profiles into JUnit tests.

    So I know that if I annote a class in the following way:

    @Profile("stub")
    @Repository
    public class StubAccountRepository implements AccountRepository {
    
        private Logger logger = Logger.getLogger(StubAccountRepository.class);
    
        private Map<String, Account> accountsByCreditCard = new HashMap<String, Account>();
    
        /**
         * Creates a single test account with two beneficiaries. Also logs creation
         * so we know which repository we are using.
         */
        public StubAccountRepository() {
            logger.info("Creating " + getClass().getSimpleName());
            Account account = new Account("123456789", "Keith and Keri Donald");
            account.addBeneficiary("Annabelle", Percentage.valueOf("50%"));
            account.addBeneficiary("Corgan", Percentage.valueOf("50%"));
            accountsByCreditCard.put("1234123412341234", account);
        }
    
        public Account findByCreditCard(String creditCardNumber) {
            Account account = accountsByCreditCard.get(creditCardNumber);
            if (account == null) {
                throw new EmptyResultDataAccessException(1);
            }
            return account;
        }
    
        public void updateBeneficiaries(Account account) {
            // nothing to do, everything is in memory
        }
    }
    

    I am declaring a service bean that belongs to the stub profile.

    So, if my test class is something like this:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=TestInfrastructureConfig.class)
    @ActiveProfiles("stub")
    public class RewardNetworkTests {
        .....................................
        .....................................
        .....................................
    }
    

    it means that it will be used the beans bean that belong to the stub profile and the bean that not have a profile. Is it right or am I missing something?

    What happens if instead use the @ActiveProfiles annotation on a class (whose instance will be a Spring bean) I use it on a Java Configuration Class?

    Something like it:

    @Configuration
    @Profile("jdbc-dev")
    public class TestInfrastructureDevConfig {
    
        /**
         * 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();
        }   
    }
    

    What exactly do? I think that all the beans configured in this class will belong to the jdbc-dev profile, but I am not sure about it. Can you give me more information about this thing?

    Why I have to use the @Profile annotation on a **configuration class* instead annotate directly my beans?

    Tnx