Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing spring loaded properties in BeanDefinitionRegistryPostProcessor

How can I access properties loaded by <context:property-placeholder> in BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry.

I am unable to use fields annotated with @Value, as they do not seem to be initialized (their values are null).

like image 882
Mukund Jalan Avatar asked Oct 23 '25 20:10

Mukund Jalan


1 Answers

Setting the value of fields annotated with @Value happens only after the post-processing of the BeanDefinitionRegistry, meaning they are not usable at this stage of the initialization process.

You can however explicitly scan the configuration environment and read the relevant properties' values from there, then use them in your dynamic bean definitions.

To gain access to the configuration environment, you can create your BeanDefinitionRegistryPostProcessor in a method annotated with @Bean, that takes the ConfigurableEnvironment as a parameter.

See the following example:

package com.sample.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;

@Configuration
public class DynamicBeanConfig {

    private static final String PROPERTY_KEY = "somename"; 

    @Bean
    public BeanDefinitionRegistryPostProcessor beanPostProcessor(ConfigurableEnvironment environment) {
        return new PostProcessor(environment);
    }

    class PostProcessor implements BeanDefinitionRegistryPostProcessor {

        private String propertyValue;

        /*
         * Reads property value from the configuration, then stores it
         */
        public PostProcessor(ConfigurableEnvironment environment) {
            propertyValue = readProperty(environment);
        }

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}

        /*
         * Creates the bean definition dynamically (using the configuration value), then registers it
         */
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SampleDynamicBean.class);
            builder.addPropertyValue("property", propertyValue);
            registry.registerBeanDefinition("sampleDynamicBean", builder.getBeanDefinition());
        }

        /*
         * Iterates over all configuration sources, looking for the property value.
         * As Spring orders the property sources by relevance, the value of the first 
         * encountered property with the correct name is read and returned.
         */
        private String readProperty(ConfigurableEnvironment environment) {
            for (PropertySource<?> source : environment.getPropertySources()) {
                if (source instanceof EnumerablePropertySource) {
                    EnumerablePropertySource<?> propertySource = (EnumerablePropertySource<?>) source;
                    for (String property : propertySource.getPropertyNames()) {
                        if (PROPERTY_KEY.equals(property))
                        {
                            return (String)propertySource.getProperty(PROPERTY_KEY);
                        }
                    }
                }
            }
            throw new IllegalStateException("Unable to determine value of property " + PROPERTY_KEY);
        }

    }

    class SampleDynamicBean {
        private String property;

        public void setProperty(String property)
        {
            this.property = property;
        }

        public String getMessage()
        {
            return "This message is produced by a dynamic bean, it includes " + property;
        }

    }

}

The sample code is adapted from this blog post, https://scanningpages.wordpress.com/2017/07/28/spring-dynamic-beans/

like image 127
radu Avatar answered Oct 27 '25 06:10

radu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!