I am trying to create something which will auto-create beans based on configurable properties (from application.yml
and the like).
Since I can't just access the properties component like I normally would in the BeanFactoryPostProcessor
, I'm kind of stumped how I can access them.
How can I access application properties in BeanFactoryPostProcessor
?
If you want to access properties in a type-safe manner in a BeanFactoryPostProcessor
you'll need to bind them from the Environment
yourself using the Binder
API. This is essentially what Boot itself does to support @ConfigurationProperties
beans.
Your BeanFactoryPostProcessor
would look something like this:
@Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor(
Environment environment) {
return new BeanFactoryPostProcessor() {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
BindResult<ExampleProperties> result = Binder.get(environment)
.bind("com.example.prefix", ExampleProperties.class);
ExampleProperties properties = result.get();
// Use the properties to post-process the bean factory as needed
}
};
}
I didn't want to use the solution above that used an @Bean
producer method since it's contrary to the recommended approach of annotating a class with @Component
and picking up via component scanning. Fortunately it's straightforward to do that by implementing EnvironmentAware
:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ConditionalDependencyPostProcessor implements BeanFactoryPostProcessor, EnvironmentAware {
/** Logger instance. */
private final Logger logger = LoggerFactory.getLogger(ConditionalDependencyPostProcessor.class);
/** Spring environment. */
private Environment environment;
@Override
public void setEnvironment(final Environment env) {
environment = env;
}
...
private boolean hasRequiredProfiles(final DependencyInfo info) {
final Set<String> activeProfiles = new HashSet<>(Arrays.asList(environment.getActiveProfiles()));
for (String profile : info.requiredProfiles) {
if (!activeProfiles.contains(profile)) {
return false;
}
}
return true;
}
I should note what did NOT work: trying to autowire an Environment
constructor argument. BeanFactoryPostProcessors require a no-argument constructor and don't support autowiring, which is itself a feature implemented by another post processor, AutowiredAnnotationBeanPostProcessor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With