Spring cloud config client refresh process

  springcloud

Overall process (Triggers the EnvironmentChangeEvent event)

clipboard.png

In response to the EnvironmentChangeEvent event (Rebind)

clipboard.png

RefreshEndpoint

@ConfigurationProperties(prefix = "endpoints.refresh", ignoreUnknownFields = false)
@ManagedResource
public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {

    private ContextRefresher contextRefresher;

    public RefreshEndpoint(ContextRefresher contextRefresher) {
        super("refresh");
        this.contextRefresher = contextRefresher;
    }

    @ManagedOperation
    public String[] refresh() {
        Set<String> keys = contextRefresher.refresh();
        return keys.toArray(new String[keys.size()]);
    }

    @Override
    public Collection<String> invoke() {
        return Arrays.asList(refresh());
    }

}

ContextRefresher.refresh

public synchronized Set<String> refresh() {
        Map<String, Object> before = extract(
                this.context.getEnvironment().getPropertySources());
        addConfigFilesToEnvironment();
        Set<String> keys = changes(before,
                extract(this.context.getEnvironment().getPropertySources())).keySet();
        this.context.publishEvent(new EnvironmentChangeEvent(keys));
        this.scope.refreshAll();
        return keys;
    }

ConfigurationPropertiesRebinder.onApplicationEvent(EnvironmentChangeEvent)

@Component
@ManagedResource
public class ConfigurationPropertiesRebinder
        implements ApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {

    private ConfigurationPropertiesBeans beans;

    private ConfigurationPropertiesBindingPostProcessor binder;

    private ApplicationContext applicationContext;

    private Map<String, Exception> errors = new ConcurrentHashMap<>();

    public ConfigurationPropertiesRebinder(
            ConfigurationPropertiesBindingPostProcessor binder,
            ConfigurationPropertiesBeans beans) {
        this.binder = binder;
        this.beans = beans;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * A map of bean name to errors when instantiating the bean.
     *
     * @return the errors accumulated since the latest destroy
     */
    public Map<String, Exception> getErrors() {
        return this.errors;
    }

    @ManagedOperation
    public void rebind() {
        this.errors.clear();
        for (String name : this.beans.getBeanNames()) {
            rebind(name);
        }
    }

    @ManagedOperation
    public boolean rebind(String name) {
        if (!this.beans.getBeanNames().contains(name)) {
            return false;
        }
        if (this.applicationContext != null) {
            try {
                Object bean = this.applicationContext.getBean(name);
                this.binder.postProcessBeforeInitialization(bean, name);
                this.applicationContext.getAutowireCapableBeanFactory()
                        .initializeBean(bean, name);
                return true;
            }
            catch (RuntimeException e) {
                this.errors.put(name, e);
                throw e;
            }
        }
        return false;
    }

    @ManagedAttribute
    public Set<String> getBeanNames() {
        return new HashSet<String>(this.beans.getBeanNames());
    }

    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        rebind();
    }

}

ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization

public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        ConfigurationProperties annotation = AnnotationUtils
                .findAnnotation(bean.getClass(), ConfigurationProperties.class);
        if (annotation != null) {
            postProcessBeforeInitialization(bean, beanName, annotation);
        }
        annotation = this.beans.findFactoryAnnotation(beanName,
                ConfigurationProperties.class);
        if (annotation != null) {
            postProcessBeforeInitialization(bean, beanName, annotation);
        }
        return bean;
    }

AbstractAutowireCapableBeanFactory.initializeBean

/**
     * Initialize the given bean instance, applying factory callbacks
     * as well as init methods and bean post processors.
     * <p>Called from {@link #createBean} for traditionally defined beans,
     * and from {@link #initializeBean} for existing bean instances.
     * @param beanName the bean name in the factory (for debugging purposes)
     * @param bean the new bean instance we may need to initialize
     * @param mbd the bean definition that the bean was created with
     * (can also be {@code null}, if given an existing bean instance)
     * @return the initialized bean instance (potentially wrapped)
     * @see BeanNameAware
     * @see BeanClassLoaderAware
     * @see BeanFactoryAware
     * @see #applyBeanPostProcessorsBeforeInitialization
     * @see #invokeInitMethods
     * @see #applyBeanPostProcessorsAfterInitialization
     */
    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }

        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

doc