Load spring boot app properties from database

后端 未结 3 2061
傲寒
傲寒 2020-12-24 15:17

I need you to advice me with this issue, in a spring boot application I load some properties from database like (cron periods, email data), I need to export these properties

3条回答
  •  死守一世寂寞
    2020-12-24 15:45

    I think it’s a good idea to use BeanPostProcessor and Binder so that you don’t need to list all the attributes you want to read. The following code refers to ConfigurationPropertiesBindingPostProcessor.

    public class PropertiesInsideDatabaseInitializer implements BeanPostProcessor, InitializingBean, ApplicationContextAware {
    
        private JdbcTemplate jdbcTemplate;
        private ApplicationContext applicationContext;
        private BeanDefinitionRegistry registry;
        private Map systemConfigMap = new HashMap<>();
    
        private final String propertySourceName = "propertiesInsideDatabase";
    
        public PropertiesInsideDatabaseInitializer(JdbcTemplate jdbcTemplate){
            this.jdbcTemplate = jdbcTemplate;
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
            return bean;
        }
    
        private void bind(ConfigurationPropertiesBean propertiesBean) {
            if (propertiesBean == null || hasBoundValueObject(propertiesBean.getName())) {
                return;
            }
            Assert.state(propertiesBean.getBindMethod() == ConfigurationPropertiesBean.BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
                    + propertiesBean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
            try {
                Bindable target = propertiesBean.asBindTarget();
                ConfigurationProperties annotation = propertiesBean.getAnnotation();
                BindHandler bindHandler = new IgnoreTopLevelConverterNotFoundBindHandler();
                MutablePropertySources mutablePropertySources = new MutablePropertySources();
                mutablePropertySources.addLast(new MapPropertySource(propertySourceName, systemConfigMap));
                Binder binder = new Binder(ConfigurationPropertySources.from(mutablePropertySources), new PropertySourcesPlaceholdersResolver(mutablePropertySources),
                        ApplicationConversionService.getSharedInstance(), getPropertyEditorInitializer(), null);
                binder.bind(annotation.prefix(), target, bindHandler);
            }
            catch (Exception ex) {
                throw new BeanCreationException("", ex);
            }
        }
    
        private Consumer getPropertyEditorInitializer() {
            if (this.applicationContext instanceof ConfigurableApplicationContext) {
                return ((ConfigurableApplicationContext) this.applicationContext).getBeanFactory()::copyRegisteredEditorsTo;
            }
            return null;
        }
    
        private boolean hasBoundValueObject(String beanName) {
            return this.registry.containsBeanDefinition(beanName) && this.registry
                    .getBeanDefinition(beanName).getClass().getName().contains("ConfigurationPropertiesValueObjectBeanDefinition");
        }
    
        @Override
        public void afterPropertiesSet() {
            String sql = "SELECT key, value from system_config";
            List> maps = jdbcTemplate.queryForList(sql);
            for (Map map : maps) {
                String key = String.valueOf(map.get("key"));
                Object value = map.get("value");
                systemConfigMap.put(key, value);
            }
            this.registry = (BeanDefinitionRegistry) this.applicationContext.getAutowireCapableBeanFactory();
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }
    

    Modifying the PropertySources in Environment can also be achieved. The BeanPostProcessor interface is implemented to initialize it before creating the Bean

    public class PropertiesInsideDatabaseInitializer implements BeanPostProcessor, InitializingBean, EnvironmentAware {
    
        private JdbcTemplate jdbcTemplate;
        private ConfigurableEnvironment environment;
    
        private final String propertySourceName = "propertiesInsideDatabase";
    
    
        public PropertiesInsideDatabaseInitializer(JdbcTemplate jdbcTemplate){
            this.jdbcTemplate = jdbcTemplate;
        }
    
        @Override
        public void afterPropertiesSet() {
            if(environment != null){
                Map systemConfigMap = new HashMap<>();
                String sql = "SELECT key, value from system_config";
                List> maps = jdbcTemplate.queryForList(sql);
                for (Map map : maps) {
                    String key = String.valueOf(map.get("key"));
                    Object value = map.get("value");
                    systemConfigMap.put(key, value);
                }
                environment.getPropertySources().addFirst(new MapPropertySource(propertySourceName, systemConfigMap));
            }
        }
    
        @Override
        public void setEnvironment(Environment environment) {
            if(environment instanceof ConfigurableEnvironment){
                this.environment = (ConfigurableEnvironment) environment;
            }
        }
    }
    

提交回复
热议问题