SATURN  RING  STATION

At a distant space view post, we chat about codes.

Spring Boot select bean by properties file in runtime.

It’s very convenience that we can switch our beans using @Profile annotation and set them in application.properties. However…

One draw back is that the beans marked with @profile are either being created or not in application-context. What happens when you need all those beans to be created in a “hybrid” environment? Well, when we @Autowired that specified bean, we get “multiple beans of same type” error. If we add @Qualifier to it, then it will complains “referenced bean ‘beanName’ not found” back in “non-hybrid” environment.

Here is an annotation only quick fix.

    @Resource(name = "${spring.profiles.active}")
    PersistenceService persistenceService;

It can be any field in your properties file. Instead of creating a new field I just reuse the spring.profiles.active. Since we have to come up names for all @Profile annotation. let them be the bean names.

let’s have an exmaple:

this is a web crawler that has three persistence services. One stores images in local folder, one stores images in a DB, and last one store them in both folder and DB (“hybrid” environment).

@Service
@Profile({"dBService", "doBothService"})
public class DBService implements PersistenceService {

    @Autowired
    private ImageRepository imageRepository;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    ...

 

@Service
@Profile({"localFileService", "doBothService"})
public class LocalFileService implements PersistenceService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    ...

 

@Service
@Profile("doBothService")
public class DoBothService implements PersistenceService {

    @Autowired
    private DBService dbService;
    @Autowired
    private LocalFileService localFileService;

    @Override
    public void saveImage(String url, byte[] imageBytes) {
        localFileService.saveImage(url, imageBytes);
        dbService.saveImage(url, imageBytes);
    }
}

application.properties

...

# localFileService for using LocalFileService class to store images in local images folder.
# dBService for using DBService class to store images in a PostgreSQL DB.
# doBothService for using DoBothService class to store images in both local images folder and a PostgreSQL DB.
spring.profiles.active=doBothService

...

Other way to do it will be writing xml. Pick different xml based on an external properties file or command. Yet another way will be writing a custom Condition class doing properties name check and with @Conditional on beans.

Btw this whole app is on GitHub, in CrawlerWithDB folder.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Spring Boot select bean by properties file in runtime.