apollo 动态监听配置文件

Posted bohu83

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了apollo 动态监听配置文件相关的知识,希望对你有一定的参考价值。

1 默认的@Value  就能自动监听更新。底层也是依赖于ConfigChangeListener。

缺点是不够灵活,如果你配置了一堆数据,监听到更新做业务处理。可以使用@ApolloConfigChangeListener。

******************

有个隐藏的坑,发现每次更新依靠@Value  不一定获取到最新的值。重复修改几次,有事可以有事不行,靠changeEvent 获取的新旧值更稳妥些。

****************

底层实现:

public class ApolloAnnotationProcessor extends ApolloProcessor {
    public ApolloAnnotationProcessor() {
    }

    protected void processField(Object bean, String beanName, Field field) {
        ApolloConfig annotation = (ApolloConfig)AnnotationUtils.getAnnotation(field, ApolloConfig.class);
        if (annotation != null) {
            Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()), "Invalid type: %s for field: %s, should be Config", new Object[]{field.getType(), field});
            String namespace = annotation.value();
            Config config = ConfigService.getConfig(namespace);
            ReflectionUtils.makeAccessible(field);
            ReflectionUtils.setField(field, bean, config);
        }
    }

    protected void processMethod(final Object bean, String beanName, final Method method) {
        ApolloConfigChangeListener annotation = (ApolloConfigChangeListener)AnnotationUtils.findAnnotation(method, ApolloConfigChangeListener.class);
        if (annotation != null) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            Preconditions.checkArgument(parameterTypes.length == 1, "Invalid number of parameters: %s for method: %s, should be 1", new Object[]{parameterTypes.length, method});
            Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]), "Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", new Object[]{parameterTypes[0], method});
            ReflectionUtils.makeAccessible(method);
            String[] namespaces = annotation.value();
            String[] annotatedInterestedKeys = annotation.interestedKeys();
            String[] annotatedInterestedKeyPrefixes = annotation.interestedKeyPrefixes();
            ConfigChangeListener configChangeListener = new ConfigChangeListener() {
                public void onChange(ConfigChangeEvent changeEvent) {
                    ReflectionUtils.invokeMethod(method, bean, new Object[]{changeEvent});
                }
            };
            Set<String> interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null;
            Set<String> interestedKeyPrefixes = annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) : null;
            String[] var12 = namespaces;
            int var13 = namespaces.length;

            for(int var14 = 0; var14 < var13; ++var14) {
                String namespace = var12[var14];
                Config config = ConfigService.getConfig(namespace);
                if (interestedKeys == null && interestedKeyPrefixes == null) {
                    config.addChangeListener(configChangeListener);
                } else {
                    config.addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes);
                }
            }

        }
    }
}

可以看到,除了关于namespace外如“application.properties”,

这里有关的两个属性:interestedKeys、interestedKeyPrefixes

设置了就取关心的值,不设置就监控整个文件。

*********************************

@Value 相关的类:

ApolloProcessor 实现了BeanPostProcessor,在postProcessBeforeInitialization中对字段和方法进行了处理。

public abstract class ApolloProcessor implements BeanPostProcessor, PriorityOrdered {
    public ApolloProcessor() {
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class clazz = bean.getClass();
        Iterator var4 = this.findAllField(clazz).iterator();

        while(var4.hasNext()) {
            Field field = (Field)var4.next();
            this.processField(bean, beanName, field);
        }

        var4 = this.findAllMethod(clazz).iterator();

        while(var4.hasNext()) {
            Method method = (Method)var4.next();
            this.processMethod(bean, beanName, method);
        }

        return bean;
    }

在ApolloProcessor 子类SpringValueProcessor中processField、和 processMethod 对注解@Value进行了处理

ublic class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor, BeanFactoryAware {
    private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class);
    private final ConfigUtil configUtil = (ConfigUtil)ApolloInjector.getInstance(ConfigUtil.class);
    private final PlaceholderHelper placeholderHelper = (PlaceholderHelper)SpringInjector.getInstance(PlaceholderHelper.class);
    private final SpringValueRegistry springValueRegistry = (SpringValueRegistry)SpringInjector.getInstance(SpringValueRegistry.class);
    private BeanFactory beanFactory;
    private Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions = LinkedListMultimap.create();

    public SpringValueProcessor() {
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (this.configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && beanFactory instanceof BeanDefinitionRegistry) {
            this.beanName2SpringValueDefinitions = SpringValueDefinitionProcessor.getBeanName2SpringValueDefinitions((BeanDefinitionRegistry)beanFactory);
        }

    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (this.configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
            super.postProcessBeforeInitialization(bean, beanName);
            this.processBeanPropertyValues(bean, beanName);
        }

        return bean;
    }

    protected void processField(Object bean, String beanName, Field field) {
        Value value = (Value)field.getAnnotation(Value.class);
        if (value != null) {
            Set<String> keys = this.placeholderHelper.extractPlaceholderKeys(value.value());
            if (!keys.isEmpty()) {
                Iterator var6 = keys.iterator();

                while(var6.hasNext()) {
                    String key = (String)var6.next();
                    SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
                    this.springValueRegistry.register(this.beanFactory, key, springValue);
                    logger.debug("Monitoring {}", springValue);
                }

            }
        }
    }

    protected void processMethod(Object bean, String beanName, Method method) {
        Value value = (Value)method.getAnnotation(Value.class);
        if (value != null) {
            if (method.getAnnotation(Bean.class) == null) {
                if (method.getParameterTypes().length != 1) {
                    logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters", new Object[]{bean.getClass().getName(), method.getName(), method.getParameterTypes().length});
                } else {
                    Set<String> keys = this.placeholderHelper.extractPlaceholderKeys(value.value());
                    if (!keys.isEmpty()) {
                        Iterator var6 = keys.iterator();

                        while(var6.hasNext()) {
                            String key = (String)var6.next();
                            SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
                            this.springValueRegistry.register(this.beanFactory, key, springValue);
                            logger.info("Monitoring {}", springValue);
                        }

                    }
                }
            }
        }
    }

判断字段是否被@Value标记,不为空的情况下解析@Value注解里面设置的value 。

构造SpringValue对象 ,并存到SpringValueRegistry。

在ApolloProcessor 子类ApolloAnnotationProcessor中processMethod对注解@ApolloConfigChangeListener进行了处理

public class AutoUpdateConfigChangeListener implements ConfigChangeListener {
    private static final Logger logger = LoggerFactory.getLogger(AutoUpdateConfigChangeListener.class);
    private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter = this.testTypeConverterHasConvertIfNecessaryWithFieldParameter();
    private final Environment environment;
    private final ConfigurableBeanFactory beanFactory;
    private final TypeConverter typeConverter;
    private final PlaceholderHelper placeholderHelper;
    private final SpringValueRegistry springValueRegistry;
    private final Gson gson;

    public AutoUpdateConfigChangeListener(Environment environment, ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        this.typeConverter = this.beanFactory.getTypeConverter();
        this.environment = environment;
        this.placeholderHelper = (PlaceholderHelper)SpringInjector.getInstance(PlaceholderHelper.class);
        this.springValueRegistry = (SpringValueRegistry)SpringInjector.getInstance(SpringValueRegistry.class);
        this.gson = new Gson();
    }

    public void onChange(ConfigChangeEvent changeEvent) {
        Set<String> keys = changeEvent.changedKeys();
        if (!CollectionUtils.isEmpty(keys)) {
            Iterator var3 = keys.iterator();

            while(true) {
                Collection targetValues;
                do {
                    do {
                        if (!var3.hasNext()) {
                            return;
                        }

                        String key = (String)var3.next();
                        targetValues = this.springValueRegistry.get(this.beanFactory, key);
                    } while(targetValues == null);
                } while(targetValues.isEmpty());

                Iterator var6 = targetValues.iterator();

                while(var6.hasNext()) {
                    SpringValue val = (SpringValue)var6.next();
                    this.updateSpringValue(val);
                }
            }
        }
    }
changeEvent.changedKeys();获取到变更keys

遍历key,通过targetValues = this.springValueRegistry.get取值。

通过updateSpringValue 更新value。

致谢:

https://blog.csdn.net/u013445220/article/details/95590749

 

以上是关于apollo 动态监听配置文件的主要内容,如果未能解决你的问题,请参考以下文章

Sentinel动态配置

Apollo在程序中监听配置变化

Apollo在程序中监听配置变化

Apollo在程序中监听配置变化

分布式配置中心 携程 apollo

Apollo Codegen 没有找到生成代码的操作或片段