Max
Max

Reputation: 1342

How to provide different beans depending on runtime parameter using @Bean method

I am trying create a @Configuration factory bean that should create other (prototype) beans depending on a runtime parameter. I want to use spring java-based configuration but somehow I could not make it work.

Here is an example:

enum PetType{CAT,DOG;}

abstract class Pet {    
}

@Component
@Scope("prototype")
class Cat extends Pet{
}

@Component
@Scope("prototype")
class dog extends Pet{
}

@Configuration
public class PetFactory{    
    @Bean
    @Scope("prototype")
    public Pet pet(PetType type){
        if(type == CAT){
            return new Cat();
        }else
            return new Dog();
    }
}

petFactory.animal(PetType.CAT);

I checked spring docs and all related questions asked here but I end up in the case of supplying runtime parameters to the created bean. And I need to supply runtime parameters to the factory that must use them to create different beans.

EDIT: Seems (currently) there is no way to define a parameter to a @Bean annotated method as "runtime". Spring assumes method parameters will be used as constructor args for the new bean and so it tries to satisfy this dependency with container-managed beans.

Upvotes: 5

Views: 3160

Answers (3)

ydrozhdzhal
ydrozhdzhal

Reputation: 164

You can just @Autowire your PetFactory bean into required bean and call animal() method with required type in runtime, like in the following approach:

@Configuration    
public class AppConfiguration {

    @Bean
    @Scope("prototype")
    public Pet getPet(PetType type) {

        if(type == CAT){
            return new Cat();
        } else
            return new Dog();
    }

}

//...
// Then in required class
@Service
public class PetService {

    @Autowired
    private AppConfiguration configuration;

    //.....

    public Pet getPetByType(PetType type) {
        return configuration.getPet(type);
    }

}

Upvotes: 1

Jukka
Jukka

Reputation: 4663

Try using @Configurable:

class Factory {

    Pet newPetOfType(PetType type) {
        switch (type) {
            case CAT: return new Cat();
            ...
        }
    }

    @Configurable
    private static class Cat extends Pet {
        @Autowired private Prop prop;
        ...
    }
}

Upvotes: 1

Scott
Scott

Reputation: 9488

This seems like it could be a good use of the Spring Profiles feature. Here you can read about Java configurations, and here about XML Profiles.

Your profile would define a Pet bean. Your factory could then wire that bean in.

To modify which profile you use, simply add: -Dspring.profiles.active=dog or -Dspring.profiles.active=cat (or whatever you name them).

Upvotes: 3

Related Questions