org.zodiac.autoconfigure.bootstrap.AppConfigurationPropertiesRebinderAutoConfiguration Maven / Gradle / Ivy
package org.zodiac.autoconfigure.bootstrap;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.zodiac.core.context.properties.AppConfigurationPropertiesBeans;
import org.zodiac.core.context.properties.AppConfigurationPropertiesRebinder;
@SpringBootConfiguration
@ConditionalOnBean(value = {ConfigurationPropertiesBindingPostProcessor.class})
public class AppConfigurationPropertiesRebinderAutoConfiguration
implements ApplicationContextAware, SmartInitializingSingleton {
private ApplicationContext context;
public AppConfigurationPropertiesRebinderAutoConfiguration() {
super();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.context = applicationContext;
}
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
protected static AppConfigurationPropertiesBeans appConfigurationPropertiesBeans(ApplicationContext context) {
// Since this is a BeanPostProcessor we have to be super careful not to
// cause a cascade of bean instantiation. Knowing the *name* of the beans we
// need is super optimal, but a little brittle (unfortunately we have no
// choice).
ConfigurationBeanFactoryMetadata metaData =
context.getBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, ConfigurationBeanFactoryMetadata.class);
AppConfigurationPropertiesBeans beans = new AppConfigurationPropertiesBeans();
beans.setBeanMetaDataStore(metaData);
return beans;
}
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
protected AppConfigurationPropertiesRebinder appConfigurationPropertiesRebinder(AppConfigurationPropertiesBeans beans) {
AppConfigurationPropertiesRebinder rebinder = new AppConfigurationPropertiesRebinder(beans);
return rebinder;
}
@Override
public void afterSingletonsInstantiated() {
// After all beans are initialized explicitly rebind beans from the parent
// so that changes during the initialization of the current context are
// reflected. In particular this can be important when low level services like
// decryption are bootstrapped in the parent, but need to change their
// configuration before the child context is processed.
if (this.context.getParent() != null) {
// TODO: make this optional? (E.g. when creating child contexts that prefer to
// be isolated.)
AppConfigurationPropertiesRebinder rebinder = this.context.getBean(AppConfigurationPropertiesRebinder.class);
for (String name : this.context.getParent().getBeanDefinitionNames()) {
rebinder.rebind(name);
}
}
}
}