apollo·实时参数更新·追根溯源【基于-监听器模式·AutoUpdateConfigChangeListener为起点·源码分析】

package com.ctrip.framework.apollo.enums;
// 变更类型
public enum PropertyChangeType {
    ADDED,		// 新增
    MODIFIED,	// 更新
    DELETED;	// 删除

    private PropertyChangeType() {
    }
}
package com.ctrip.framework.apollo.model;

import com.ctrip.framework.apollo.enums.PropertyChangeType;

// 事件中绑定的数据,此为:变更数据
public class ConfigChange {
    // 关键key
    private final String namespace;
    // 属性名称
    private final String propertyName;
    // 旧值
    private String oldValue;
    // 新值
    private String newValue;
    // 变更类型
    private PropertyChangeType changeType;

    public ConfigChange(String namespace, 
                        String propertyName, 
                        String oldValue, 
                        String newValue, 
                        PropertyChangeType changeType) {
        this.namespace = namespace;
        this.propertyName = propertyName;
        this.oldValue = oldValue;
        this.newValue = newValue;
        this.changeType = changeType;
    }

    public String getPropertyName() {
        return this.propertyName;
    }

    public String getOldValue() {
        return this.oldValue;
    }

    public String getNewValue() {
        return this.newValue;
    }

    public PropertyChangeType getChangeType() {
        return this.changeType;
    }

    public void setOldValue(String oldValue) {
        this.oldValue = oldValue;
    }

    public void setNewValue(String newValue) {
        this.newValue = newValue;
    }

    public void setChangeType(PropertyChangeType changeType) {
        this.changeType = changeType;
    }

    public String getNamespace() {
        return this.namespace;
    }
    // 格式化输出
    public String toString() {
        StringBuilder sb = new StringBuilder("ConfigChange{");
        sb.append("namespace='").append(this.namespace).append('\'');
        sb.append(", propertyName='").append(this.propertyName).append('\'');
        sb.append(", oldValue='").append(this.oldValue).append('\'');
        sb.append(", newValue='").append(this.newValue).append('\'');
        sb.append(", changeType=").append(this.changeType);
        sb.append('}');
        return sb.toString();
    }
}
package com.ctrip.framework.apollo.model;

import java.util.Map;
import java.util.Set;

// 配置数据变更事件
public class ConfigChangeEvent {
    // 当前事件,属于哪一个namespace
    private final String m_namespace;
    // 当前事件,有哪些变更数据(是一个map)
    private final Map<String, ConfigChange> m_changes;

    // 构造器注入
    public ConfigChangeEvent(/**具体的namespace**/String namespace, 
                             /**涉及到的变更内容**/Map<String, ConfigChange> changes) {
        this.m_namespace = namespace;
        this.m_changes = changes;
    }

    // 拿到当前事件的变更Keys
    public Set<String> changedKeys() {
        return this.m_changes.keySet();
    }

    // 根据变更key拿到具体的变更内容
    public ConfigChange getChange(String key) {
        return (ConfigChange)this.m_changes.get(key);
    }

    // 检测具体的key是否发生变化(有变化的话,当前事件绑定的变更数据中会有该key的数据,没有则说明,该key无变化)
    public boolean isChanged(String key) {
        return this.m_changes.containsKey(key);
    }

    // 拿到当前事件对应的namespace
    public String getNamespace() {
        return this.m_namespace;
    }
}
package com.ctrip.framework.apollo.spring.property;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import org.springframework.core.MethodParameter;

// 属性值对象
public class SpringValue {
    // 方法参数
    private MethodParameter methodParameter;
    // 属性
    private Field field;
    // 弱引用
    private WeakReference<Object> beanRef;
    // bean名称
    private String beanName;
    // key
    private String key;
    // 占位符
    private String placeholder;
    // 目标类型
    private Class<?> targetType;
    // 通用类型
    private Type genericType;
    // Json否
    private boolean isJson;

    // 构造器注入·1
    public SpringValue(String key, String placeholder, Object bean, String beanName, Field field, boolean isJson) {
        this.beanRef = new WeakReference(bean);
        this.beanName = beanName;
        this.field = field;
        this.key = key;
        this.placeholder = placeholder;
        this.targetType = field.getType();
        this.isJson = isJson;
        if (isJson) {
            this.genericType = field.getGenericType();
        }

    }
    // 构造器注入·2
    public SpringValue(String key, String placeholder, Object bean, String beanName, Method method, boolean isJson) {
        this.beanRef = new WeakReference(bean);
        this.beanName = beanName;
        this.methodParameter = new MethodParameter(method, 0);
        this.key = key;
        this.placeholder = placeholder;
        Class<?>[] paramTps = method.getParameterTypes();
        this.targetType = paramTps[0];
        this.isJson = isJson;
        if (isJson) {
            this.genericType = method.getGenericParameterTypes()[0];
        }

    }

    // 更新当前属性值
    public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
        if (this.isField()) {
            this.injectField(newVal);
        } else {
            this.injectMethod(newVal);
        }
    }

    private void injectField(Object newVal) throws IllegalAccessException {
        Object bean = this.beanRef.get();
        if (bean != null) {
            boolean accessible = this.field.isAccessible();
            this.field.setAccessible(true);
            this.field.set(bean, newVal);
            this.field.setAccessible(accessible);
        }
    }

    private void injectMethod(Object newVal) throws InvocationTargetException, IllegalAccessException {
        Object bean = this.beanRef.get();
        if (bean != null) {
            this.methodParameter.getMethod().invoke(bean, newVal);
        }
    }

    public String getBeanName() {
        return this.beanName;
    }

    public Class<?> getTargetType() {
        return this.targetType;
    }

    public String getPlaceholder() {
        return this.placeholder;
    }

    public MethodParameter getMethodParameter() {
        return this.methodParameter;
    }

    // 是否是属性
    public boolean isField() {
        return this.field != null;
    }

    public Field getField() {
        return this.field;
    }

    public Type getGenericType() {
        return this.genericType;
    }

    public boolean isJson() {
        return this.isJson;
    }

    // 是否失效判定:当前对象是否存在弱引用
    boolean isTargetBeanValid() {
        return this.beanRef.get() != null;
    }

    public String toString() {
        Object bean = this.beanRef.get();
        if (bean == null) {
            return "";
        } else {
            return this.isField() ? String.format("key: %s, beanName: %s, field: %s.%s", this.key, this.beanName, bean.getClass().getName(), this.field.getName()) : String.format("key: %s, beanName: %s, method: %s.%s", this.key, this.beanName, bean.getClass().getName(), this.methodParameter.getMethod().getName());
        }
    }
}
package com.ctrip.framework.apollo.spring.property;

import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.beans.factory.BeanFactory;

// apollo定制的@Value注册器
public class SpringValueRegistry {
    // 清理时间频率
    private static final long CLEAN_INTERVAL_IN_SECONDS = 5L;
    // 注册目标对象集合:按照注册Bean工厂对象作一级区分,然后按照Key做二级区分,且目标数据为多个
    private final Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap
    // 原子:是否完成初始化标记,默认false
    private final AtomicBoolean initialized = new AtomicBoolean(false);
    // 锁
    private final Object LOCK = new Object();

    public SpringValueRegistry() {
    }

    // 注册方法
    public void register(BeanFactory beanFactory, 		// bean工厂对象
                         String key, 					// 属性Key	
                         SpringValue springValue		// 属性值对象
    ) {
        // 如果当前已经完成注册的目标集合中含有当前Bean工厂对象
        if (!this.registry.containsKey(beanFactory)) {
            // 上锁
            synchronized(this.LOCK) {
                // 如果当前注册器目标数据列表中,没有找到该Bean工厂对象
                if (!this.registry.containsKey(beanFactory)) {
                    // 则完成注册(为bean工厂对象创建一个空Multimap,空容器)
                    this.registry.put(beanFactory, 
                                      Multimaps.synchronizedListMultimap(
                                              LinkedListMultimap.create()
                                      )
                     );
                }
            }
        }

        // 开始往注册的目标集合灌数据:数据结构如:<beanFactory,<key:springValue>>
        ((Multimap)this.registry.get(beanFactory)).put(key, springValue);
        // 标记,该apollo定制的@Value注册器,完成了初始化
        // 重置标记=true
        if (this.initialized.compareAndSet(false, true)) {
            // 开始初始化操作
            this.initialize();
        }

    }

    // 根据Bean工厂对象和Key获取目标属性值集合,一个key:多个value,多条数据,返回这多条value的汇总的集合对象
    public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
        Multimap<String, SpringValue> beanFactorySpringValues = (Multimap)this.registry.get(beanFactory);
        return beanFactorySpringValues == null 
                ? null 
                : beanFactorySpringValues.get(key)	// Multimap的get操作
        ;
    }

    // 私有方法:初始化逻辑
    private void initialize() {
        // 
        Executors.newSingleThreadScheduledExecutor(
            // apollo定制了一个ThreadFactory(实现ThreadFactory接口的实现类)
            // 定制了一些关于线程的操作,命名规则,创建和关闭操作等
            ApolloThreadFactory.create("SpringValueRegistry", true)
        ).scheduleAtFixedRate(
             // 具体的任务,开辟独立线程执行(从上面定制的ApolloThreadFactory中创建)
             new Runnable() {
                    public void run() {
                        try {
                            // 扫描清理动作
                            SpringValueRegistry.this.scanAndClean();
                        } catch (Throwable var2) {
                            var2.printStackTrace();
                        }
                    }
            }, 
            // 首次执行任务前的延迟时间,可以指定一个初始的等待时间,以便在启动周期性任务之前有一定的准备时间。当前:5s
            5L, 
            // 任务执行的周期时间,即两次连续任务开始执行之间的时间间隔。当前:5s
            5L, 
            // 时间单位:秒
            TimeUnit.SECONDS
        );
    }

    // 扫描清理动作
    private void scanAndClean() {

        // Map<BeanFactory, Multimap<String, SpringValue>> registry
        
        // 利用迭代器,清理数据
        // 针对数据:Multimap<key, SpringValue> 所有BeanFactory对应的的values()
        Iterator iterator = this.registry.values().iterator();

        // 当前线程正常,且迭代器中有数据
        while(!Thread.currentThread().isInterrupted() && iterator.hasNext()) {
            // 针对数据:具体的某个beanFactory对应的:Multimap<key, SpringValue>
            // 一个key:多个value,多条数据
            Multimap<String, SpringValue> springValues = (Multimap)iterator.next();
            // 继续迭代处理
            Iterator springValueIterator = springValues.entries().iterator();
            // 如果存在<key, SpringValue>数据,则继续
            while(springValueIterator.hasNext()) {
                // 拿到当前具体的<key, SpringValue>数据
                Entry<String, SpringValue> springValue = (Entry)springValueIterator.next();
                // 如果当前属性值被标记无效-失效状态(是否存在弱引用) 
                if (!((SpringValue)springValue.getValue()).isTargetBeanValid()) {                
                    // 某个具体key对应的具体SpringValue,失效了,则直接清理掉
                    springValueIterator.remove();
                }
            }
        }

    }
}
package com.ctrip.framework.apollo;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;

// 自定义了一个监听器接口(监听器模式)
public interface ConfigChangeListener {
    // 监听行为
    void onChange(/****/ConfigChangeEvent var1);
}
package com.ctrip.framework.apollo.spring.property;

import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.util.SpringInjector;
import com.google.gson.Gson;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;

// 具体监听器类
public class AutoUpdateConfigChangeListener implements /**自定义了一个监听器接口**/ConfigChangeListener {
    // 日志
    private static final Logger logger = LoggerFactory.getLogger(AutoUpdateConfigChangeListener.class);
    private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter = this.testTypeConverterHasConvertIfNecessaryWithFieldParameter();
    // 环境对象
    private final Environment environment;
    // Bean工厂类
    private final ConfigurableBeanFactory beanFactory;
    // 类型转换器
    private final TypeConverter typeConverter;
    // 占位符助手
    private final PlaceholderHelper placeholderHelper;
    // @Value注册器(管理 Spring 属性绑定,与 Apollo 配置中心集成,处理占位符解析:)
    // 与 Apollo 配置中心紧密合作,实现配置的动态更新。当 Apollo 配置中心的配置发生变化时,Apollo 客户端会通知SpringValueRegistry。
    // SpringValueRegistry接收到通知后,会查找那些依赖于变化配置的@Value注解的属性,并更新其值。这确保了应用能够实时响应配置的变化,而无需重新启动。
    private final SpringValueRegistry springValueRegistry;
    private final Gson gson;

    // 构造器注入(初始化配置)
    public AutoUpdateConfigChangeListener(Environment environment, 		// 环境对象
                                          ConfigurableListableBeanFactory beanFactory	// spring ioc bean工厂对象
    ) {
        // 注入当前适用的Bean工厂对象
        this.beanFactory = beanFactory;
        this.typeConverter = this.beanFactory.getTypeConverter();
        this.environment = environment;
        // 又见Injector技术
        this.placeholderHelper = (PlaceholderHelper)SpringInjector.getInstance(PlaceholderHelper.class);
        // apollo自定义的SpringValueRegistry
        this.springValueRegistry = (SpringValueRegistry)SpringInjector.getInstance(SpringValueRegistry.class);
        this.gson = new Gson();
    }

    // 监听器实现类-监控的动作
    public void onChange(/**监控的事件内容**/ConfigChangeEvent changeEvent) {
        // 拿到所有变更的数据Keys
        Set<String> keys = changeEvent.changedKeys();
        // 非空判定
        if (!CollectionUtils.isEmpty(keys)) {
            // 迭代
            Iterator i$ = keys.iterator();

            // 下面是while循环、do-while循环组合
            while(true) {
                // 预先放置一个空集合
                Collection targetValues;
                // go~
                do {
                    // go~
                    do {
                        // 有后续迭代内容
                        if (!i$.hasNext()) {
                            return;
                        }
                        // 拿到具体变更的key
                        String key = (String)i$.next();
                        // 通过@Value属性注册器获取该Key的值,存放到前文预置的集合对象中
                        // Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap
                        // 注册目标对象集合:按照注册Bean工厂对象作一级区分,然后按照Key做二级区分,且目标数据为多个
                        targetValues = this.springValueRegistry.get(this.beanFactory, key);
                    // 预先放置的集合为null时,进入循环  
                    } while(targetValues == null);
                // 预先放置的集合为空集合时,进入循环   
                } while(targetValues.isEmpty());


                // 针对“前文预置的集合对象”,获取它的迭代器
                Iterator i$ = targetValues.iterator();

                // 循环迭代
                while(i$.hasNext()) {
                    // 逐个拿到当前Key对应的所有数据
                    SpringValue val = (SpringValue)i$.next();
                    // 更新数据
                    this.updateSpringValue(val);
                }
            }
        }
    }

    // 更新属性数据
    private void updateSpringValue(/**传入已经明确需要更新的属性值对象**/SpringValue springValue) {
        try {
            // 拆包预处理-拿到具体的数据
            Object value = this.resolvePropertyValue(springValue);
            // 更新操作
            springValue.update(value);
            logger.info("Auto update apollo changed value successfully, new value: {}, {}", value, springValue);
        } catch (Throwable var3) {
            logger.error("Auto update apollo changed value failed, {}", springValue.toString(), var3);
        }
    }

    // 拆包预处理-拿到具体的数据
    private Object resolvePropertyValue(SpringValue springValue) {
        // 使用拆包工具(PlaceholderHelper)进行解析处理
        Object value = this.placeholderHelper.resolvePropertyValue(this.beanFactory, 
                                                                   springValue.getBeanName(), 
                                                                   springValue.getPlaceholder()
        );
        // 格式化处理:
        if (springValue.isJson()) {
            // Json
            value = this.parseJsonValue((String)value, springValue.getGenericType());
        } else if (springValue.isField()) {
            // 有属性 ???
            if (this.typeConverterHasConvertIfNecessaryWithFieldParameter) {
                // ???
                value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getField());
            } else {
                // ???
                value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType());
            }
        } else {
            // 其他
            value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getMethodParameter());
        }

        return value;
    }

    // json格式化处理
    private Object parseJsonValue(String json, Type targetType) {
        try {
            return this.gson.fromJson(json, targetType);
        } catch (Throwable var4) {
            logger.error("Parsing json '{}' to type {} failed!", new Object[]{json, targetType, var4});
            throw var4;
        }
    }

    // 类型转换测试判定
    private boolean testTypeConverterHasConvertIfNecessaryWithFieldParameter() {
        try {
            TypeConverter.class.getMethod("convertIfNecessary", Object.class, Class.class, Field.class);
            return true;
        } catch (Throwable var2) {
            return false;
        }
    }
}

现在,AutoUpdateConfigChangeListener 的具体逻辑知道了,就是监控到 apollo 配置的变动时,可以通过该类的onChange(/**监控的事件内容**/ConfigChangeEvent changeEvent)实现属性的更新。

现在还缺少一个时间触发机制和触发点?继续分析!!!

AutoUpdateConfigChangeListener.java 只是提供了自动更新字段数据的能力,因为是实时更新的,那么就是在控制从 apollo 服务端拉取数据后,都会将数据包装成CompositePropertySource 对象丢到环境对象中去

在前文中:

此处为语雀内容卡片,点击链接查看:https://www.yuque.com/xiaofengweiling/fkrpy5/heq5kl80v8m68e5w

看到注册了一堆定制的处理器

其中有一个:
 

 // 注册PropertySourcesProcessor(属性资源处理器)核心的一个
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, 
                                                               PropertySourcesProcessor.class.getName(), 
                                                               PropertySourcesProcessor.class);

接下来具体分析一下,看看里面有哪些逻辑?

package com.ctrip.framework.apollo.spring.config;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.build.ApolloInjector;
// 看到目标了
import com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener;
import com.ctrip.framework.apollo.spring.util.SpringInjector;
import com.ctrip.framework.apollo.util.ConfigUtil;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.collect.UnmodifiableIterator;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
// 定制处理器
public class PropertySourcesProcessor implements 
// 后置处理器
// 在 Spring 容器加载完 Bean 的定义信息,但在实例化 Bean 之前被调用
// 可以对 BeanDefinition 进行修改,比如修改 Bean 的属性值、添加新的属性等
BeanFactoryPostProcessor, 
// EnvironmentAware是一个接口,实现该接口的类可以感知和访问 Spring 的Environment对象
EnvironmentAware,
PriorityOrdered 
{
    // apollo的NAMESPACE_NAMES
    private static final Multimap<Integer, String> NAMESPACE_NAMES = LinkedHashMultimap.create();
    // 
    private static final Set<BeanFactory> AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES = Sets.newConcurrentHashSet();
    //
    private final ConfigPropertySourceFactory configPropertySourceFactory = (ConfigPropertySourceFactory)SpringInjector.getInstance(ConfigPropertySourceFactory.class);
    // http操作对象
    private final ConfigUtil configUtil = (ConfigUtil)ApolloInjector.getInstance(ConfigUtil.class);
    // 环境对象
    private ConfigurableEnvironment environment;

    // 构造器
    public PropertySourcesProcessor() {
    }
    // 
    public static boolean addNamespaces(Collection<String> namespaces, int order) {
        return NAMESPACE_NAMES.putAll(order, namespaces);
    }

    // 前置处理器-触发逻辑
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 初始化属性装配
        this.initializePropertySources();
        // 触发自动话属性装配特性
        this.initializeAutoUpdatePropertiesFeature(beanFactory);
    }

    // 初始化属性装配
    private void initializePropertySources() {

        // 环境中没有:“ApolloPropertySources”时
        if (!this.environment.getPropertySources().contains("ApolloPropertySources")) {
            // 创建一个:“ApolloPropertySources”
            CompositePropertySource composite = new CompositePropertySource("ApolloPropertySources");
            // 拿到apollo的NameSpaceNames数据,默认为空
            ImmutableSortedSet<Integer> orders = ImmutableSortedSet.copyOf(NAMESPACE_NAMES.keySet());
            // 迭代
            UnmodifiableIterator iterator = orders.iterator();

            // 当前默认为空,初始情况下不会触发
            while(iterator.hasNext()) {
                // 如果有数据
                int order = (Integer)iterator.next();
                Iterator i$ = NAMESPACE_NAMES.get(order).iterator();

                while(i$.hasNext()) {
                    // 拿到namespace
                    String namespace = (String)i$.next();
                    // 获取当前apollo中namespace环境数据,主动拉取一次数据
                    Config config = ConfigService.getConfig(namespace);
                    // 数据转换&装配处理
                    composite.addPropertySource(this.configPropertySourceFactory.getConfigPropertySource(namespace, config));
                }
            }

            // 清理:“拿到apollo的NameSpaceNames数据”
            NAMESPACE_NAMES.clear();

            // 服务启动时,主动从apollo服务端获取的配置数据,被打包在这个对象中了
            // 创建一个组合属性对象
            // CompositePropertySource composite = new CompositePropertySource("ApolloBootstrapPropertySources");
            // 检测到环境中有“ApolloBootstrapPropertySources”配置
            if (this.environment.getPropertySources().contains("ApolloBootstrapPropertySources")) {
                // 如果存在
                // 确保Bootstrap属性优先级
                this.ensureBootstrapPropertyPrecedence(this.environment);
                // 把“ApolloPropertySources”加到环境属性源中仅次于“ApolloBootstrapPropertySources”的位置
                // “ApolloBootstrapPropertySources”是被以首位的形式加入的
                // 所以“ApolloPropertySources”排在第二位
                this.environment.getPropertySources().addAfter("ApolloBootstrapPropertySources", composite);
            } else {
                // 如果不存在
                // 把“ApolloPropertySources”加到环境属性源的首位
                this.environment.getPropertySources().addFirst(composite);
            }

        }
    }

    // 确保Bootstrap属性优先级
    private void ensureBootstrapPropertyPrecedence(ConfigurableEnvironment environment) {
        // 拿到所有环境属性源数据
        MutablePropertySources propertySources = environment.getPropertySources();
        // 获取当前“ApolloBootstrapPropertySources”中的属性数据
        PropertySource<?> bootstrapPropertySource = propertySources.get("ApolloBootstrapPropertySources");
        // 存在 且 非首位,说明出现了问题(按照前文的逻辑:“ApolloBootstrapPropertySources”必须在首位)
        if (bootstrapPropertySource != null && propertySources.precedenceOf(bootstrapPropertySource) != 0) {
            // 清理异常配置
            propertySources.remove("ApolloBootstrapPropertySources");
            // 矫正位置,重新放置在首位
            propertySources.addFirst(bootstrapPropertySource);
        }
    }

    // 触发自动话属性装配特性 
    private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) {
        // 是否启用配置:“apollo.autoUpdateInjectedSpringProperties” 默认为true
        // 将当前的ioc加载Bean的beanFactory,收集起来
        if (this.configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES.add(beanFactory)) {
            // 创建一个监听器对象,完成监听器初始化
            AutoUpdateConfigChangeListener autoUpdateConfigChangeListener = new AutoUpdateConfigChangeListener(
                this.environment, 	// 当前环境
                beanFactory			// 当前bean工厂对象
            );
            // 拿到所有apollo配置数据
            List<ConfigPropertySource> configPropertySources = this.configPropertySourceFactory.getAllConfigPropertySources();
            // 迭代
            Iterator i$ = configPropertySources.iterator();

            while(i$.hasNext()) {
                // 具体的ConfigPropertySource
                ConfigPropertySource configPropertySource = (ConfigPropertySource)i$.next();
                // 为每一个属性添加监听器
                //  ((Config)this.source).addChangeListener(listener); 所有的监听器都是加装在具体的Config配置对象上了
                // Config是一个接口,具体的实现子类为:
                // 添加了监听器之后,还需要找到监听器的使用触发点在哪里???
                configPropertySource.addChangeListener(autoUpdateConfigChangeListener);
            }

        }
    }

    // 设置环境
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment)environment;
    }

    // 拿到排序ID
    public int getOrder() {
        return -2147483648;
    }

    // 重置
    static void reset() {
        NAMESPACE_NAMES.clear();
        AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES.clear();
    }
}

继续分析一下

// 为每一个属性添加监听器

// ((Config)this.source).addChangeListener(listener); 所有的监听器都是加装在具体的Config配置对象上了

// Config是一个接口,具体的实现子类为:

// 添加了监听器之后,还需要找到监听器的使用触发点在哪里???

configPropertySource.addChangeListener(autoUpdateConfigChangeListener);


package com.ctrip.framework.apollo;

import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.google.common.base.Function;
import java.util.Date;
import java.util.Locale;
import java.util.Set;

public interface Config {
    ......
    void addChangeListener(ConfigChangeListener var1);

    void addChangeListener(ConfigChangeListener var1, Set<String> var2);

    void addChangeListener(ConfigChangeListener var1, Set<String> var2, Set<String> var3);

    boolean removeChangeListener(ConfigChangeListener var1);
    ......
}

看一下AbstractConfig.java

package com.ctrip.framework.apollo.internals;
......

public abstract class AbstractConfig implements Config {
    private static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class);
    // 任务线程执行器
    private static final ExecutorService m_executorService = Executors.newCachedThreadPool(ApolloThreadFactory.create("Config", true));
    // 维护这所有的监听器
    private final List<ConfigChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
    // 监听器的Keys
    private final Map<ConfigChangeListener, Set<String>> m_interestedKeys = Maps.newConcurrentMap();
    // 监听器的KeyPrefixes
    private final Map<ConfigChangeListener, Set<String>> m_interestedKeyPrefixes = Maps.newConcurrentMap();
    // apollo配置数据工具
    private final ConfigUtil m_configUtil = (ConfigUtil)ApolloInjector.getInstance(ConfigUtil.class);
    // 各种缓存
    private volatile Cache<String, Integer> m_integerCache;
    private volatile Cache<String, Long> m_longCache;
    private volatile Cache<String, Short> m_shortCache;
    private volatile Cache<String, Float> m_floatCache;
    private volatile Cache<String, Double> m_doubleCache;
    private volatile Cache<String, Byte> m_byteCache;
    private volatile Cache<String, Boolean> m_booleanCache;
    private volatile Cache<String, Date> m_dateCache;
    private volatile Cache<String, Long> m_durationCache;
    private final Map<String, Cache<String, String[]>> m_arrayCache = Maps.newConcurrentMap();
    private final List<Cache> allCaches = Lists.newArrayList();
    private final AtomicLong m_configVersion = new AtomicLong();
    // 属性工厂对象
    protected PropertiesFactory propertiesFactory = (PropertiesFactory)ApolloInjector.getInstance(PropertiesFactory.class);

    public AbstractConfig() {
    }

    ......
    
    // 绑定监听器
    public void addChangeListener(ConfigChangeListener listener) {
        this.addChangeListener(listener, (Set)null);
    }
    // 绑定监听器
    public void addChangeListener(ConfigChangeListener listener, Set<String> interestedKeys) {
        this.addChangeListener(listener, interestedKeys, (Set)null);
    }
    // 绑定监听器
    public void addChangeListener(ConfigChangeListener listener, Set<String> interestedKeys, Set<String> interestedKeyPrefixes) {
        if (!this.m_listeners.contains(listener)) {
            this.m_listeners.add(listener);
            if (interestedKeys != null && !interestedKeys.isEmpty()) {
                this.m_interestedKeys.put(listener, Sets.newHashSet(interestedKeys));
            }

            if (interestedKeyPrefixes != null && !interestedKeyPrefixes.isEmpty()) {
                this.m_interestedKeyPrefixes.put(listener, Sets.newHashSet(interestedKeyPrefixes));
            }
        }

    }
    // 移除监听器
    public boolean removeChangeListener(ConfigChangeListener listener) {
        this.m_interestedKeys.remove(listener);
        this.m_interestedKeyPrefixes.remove(listener);
        return this.m_listeners.remove(listener);
    }
    
    ......

    // 监听器的触发动作
    protected void fireConfigChange(final ConfigChangeEvent changeEvent) {
        Iterator i$ = this.m_listeners.iterator();

        while(i$.hasNext()) {
            // 拿到具体的监听器
            final ConfigChangeListener listener = (ConfigChangeListener)i$.next();
            // 检测方法(异常和安全检测,放置误操作等等,此处不再深究了)
            if (this.isConfigChangeListenerInterested(listener, changeEvent)) {
                // 任务线程
                m_executorService.submit(
                    // 具体任务逻辑
                    new Runnable() {
                        public void run() {
                            String listenerName = listener.getClass().getName();
                            Transaction transaction = Tracer.newTransaction("Apollo.ConfigChangeListener", listenerName);
    
                            try {
                                // ===》触发监听器核心逻辑《===
                                listener.onChange(changeEvent);
                                transaction.setStatus("0");
                            } catch (Throwable var7) {
                                transaction.setStatus(var7);
                                Tracer.logError(var7);
                                AbstractConfig.logger.error("Failed to invoke config change listener {}", listenerName, var7);
                            } finally {
                                transaction.complete();
                            }
    
                        }
                });
            }
        }

    }

    ......
}

问题继续存在,AbstractConfig.fireConfigChange 方法是在哪里被触发的呢?

Config.java --> AbstractConfig --> DefaultConfig.java

基于这个关系脉络,继续分析!!!

......
public class DefaultConfig extends AbstractConfig implements RepositoryChangeListener {
    private static final Logger logger = LoggerFactory.getLogger(DefaultConfig.class);
    private final String m_namespace;
    private final Properties m_resourceProperties;
    private final AtomicReference<Properties> m_configProperties;
    private final ConfigRepository m_configRepository;
    private final RateLimiter m_warnLogRateLimiter;
    private volatile ConfigSourceType m_sourceType;

    public DefaultConfig(String namespace, ConfigRepository configRepository) {
        this.m_sourceType = ConfigSourceType.NONE;
        this.m_namespace = namespace;
        this.m_resourceProperties = this.loadFromResource(this.m_namespace);
        this.m_configRepository = configRepository;
        this.m_configProperties = new AtomicReference();
        this.m_warnLogRateLimiter = RateLimiter.create(0.017D);
        this.initialize();
    }

    private void initialize() {
        try {
            this.updateConfig(this.m_configRepository.getConfig(), this.m_configRepository.getSourceType());
        } catch (Throwable var5) {
            Tracer.logError(var5);
            logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.", this.m_namespace, ExceptionUtil.getDetailMessage(var5));
        } finally {
            this.m_configRepository.addChangeListener(this);
        }

    }

    // 收集监听器需要的参数:
    private Map<String, ConfigChange> updateAndCalcConfigChanges(Properties newConfigProperties,
                                                                 ConfigSourceType sourceType) {
        // 根据当前的:m_namespace + newConfigProperties.stringPropertyNames()即Key,收集对应的所有的变动List<ConfigChange>数据
        List<ConfigChange> configChanges = this.calcPropertyChanges(this.m_namespace, 
                                                                    (Properties)this.m_configProperties.get(), 
                                                                    newConfigProperties);
        // 构建真实变动容器
        Builder<String, ConfigChange> actualChanges = new Builder();
        Iterator i$ = configChanges.iterator();

        // 创建一个变动对象
        ConfigChange change;
        while(i$.hasNext()) {
            change = (ConfigChange)i$.next();
            // 为每一个变动对象写入旧属性值
            change.setOldValue(
                this.getProperty(
                    change.getPropertyName(), 
                    change.getOldValue()
                )
            );
            // 后文中
        }        

        this.updateConfig(newConfigProperties, sourceType);
        this.clearConfigCache();

        // 迭代所有变动数据
        i$ = configChanges.iterator();
        while(i$.hasNext()) {
            change = (ConfigChange)i$.next();
            // 为每一个变动对象写入新的值
            change.setNewValue(this.getProperty(change.getPropertyName(), change.getNewValue()));
            // 根据变动类型,分发处理
            switch(change.getChangeType()) {
                // 新增
                case ADDED:
                    // 新旧数据不同,有变动
                    if (!Objects.equals(change.getOldValue(), change.getNewValue())) {
                        if (change.getOldValue() != null) {
                            change.setChangeType(PropertyChangeType.MODIFIED);
                        }
                        // 收集
                        actualChanges.put(change.getPropertyName(), change);
                    }
                    break;
                // 修改    
                case MODIFIED:
                    // 新旧数据不同,有变动
                    if (!Objects.equals(change.getOldValue(), change.getNewValue())) {
                        // 收集
                        actualChanges.put(change.getPropertyName(), change);
                    }
                    break;
                // 删除    
                case DELETED:
                    // 新旧数据不同,有变动
                    if (!Objects.equals(change.getOldValue(), change.getNewValue())) {
                        if (change.getNewValue() != null) {                        
                            change.setChangeType(PropertyChangeType.MODIFIED);
                        }
                        // 收集
                        actualChanges.put(change.getPropertyName(), change);
                    }
                }
        }

        // 拿到收集到的数据返回
        return actualChanges.build();
    }

    ......

    // 线程安全:
    public synchronized void onRepositoryChange(
                                /**命名空间**/String namespace, 
                                /**新的属性数据**/ Properties newProperties
    ) {
        // 检测到新旧属性不一致,认为是发生了变化
        if (!newProperties.equals(this.m_configProperties.get())) {
            // 拿到配置属性类型
            ConfigSourceType sourceType = this.m_configRepository.getSourceType();
            // 创建一个新的属性
            Properties newConfigProperties = this.propertiesFactory.getPropertiesInstance();
            // 装配数据到新属性对象中
            newConfigProperties.putAll(newProperties);
            // 收集监听器需要的参数:
            // namespace = m_namespace
            // actualChanges中的变动对象,设置了新的值和旧的值,使得数据完整了
            Map<String, ConfigChange> actualChanges = this.updateAndCalcConfigChanges(newConfigProperties, sourceType);
            if (!actualChanges.isEmpty()) {
                // 触发事件,引起监听器的注意,从而实现属性更新
                this.fireConfigChange(new ConfigChangeEvent(this.m_namespace, actualChanges));
                Tracer.logEvent("Apollo.Client.ConfigChanges", this.m_namespace);
            }
        }
    }
    ......
}

继续向上找DefaultConfig.onRepositoryChange 方法的出发点在哪里~!!!

public synchronized void onRepositoryChange(

/**命名空间**/String namespace,

/**新的属性数据**/ Properties newProperties

) {}

onRepositoryChange 方法,一看就是针对Repository 类型的 change 监听的。

再梳理一下依赖关系:

Config.java --> AbstractConfig --> DefaultConfig.java

public class DefaultConfig

extends AbstractConfig

implements RepositoryChangeListener

DefaultConfig.java --> RepositoryChangeListener.java

发现: AbstractConfigRepository.java 中有维护监听器的触发机制:

其中维护了一个监听器的池子:
private List<RepositoryChangeListener> m_listeners;

说明一下:

RepositoryChangeListener.java 是一个接口,

DefaultConfig.java 是一个实现类,实现了 RepositoryChangeListener.java 接口


所以

private List<RepositoryChangeListener> m_listeners 中是可以存放DefaultConfig.java 对象的,(基本的装箱拆箱原则)

public class RemoteConfigRepository

extends AbstractConfigRepository

e

可以知道:
this.fireRepositoryChange(this.m_namespace, this.getConfig());

其中:


this.getConfig()拿到的数据就是上一行:this.m_configCache.set(current);中的 current 对象:

而 current 对象就是DefaultConfig 类型

详情可以查看:

此处为语雀内容卡片,点击链接查看:https://www.yuque.com/xiaofengweiling/fkrpy5/ltzdv77vbvrzdi06

所以破案了:

-----------------------------------------------------------------------------

总结一下:

(1)在前置处理器中:PropertySourcesProcessor.java 为每一个属性绑定监听器:AutoUpdateConfigChangeListener

(2)在服务启动时(主动向 apollo 服务端拉取一次)和定期刷新(定期拉取)时触发的 sync()方法中,主动触发onRepositoryChange()方法,详细流程如下:

  1. RemoteConfigRepository.java:
    1. this.fireRepositoryChange(this.m_namespace, this.getConfig());
  1. AbstractConfigRepository.java:
    1. fireRepositoryChange(String namespace, Properties newProperties);
  1. DefaultConfig.java:
    1. onRepositoryChange(String namespace, Properties newProperties);
  1. AbstractConfig.java
    1. fireConfigChange(final ConfigChangeEvent changeEvent)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成熟的小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值