Seata源码笔记(二)
基于incubartor-seata-2.x
配置相关的
ConfigurationFactory
静态代码块
initOriginConfiguration和maybeNeedOriginFileInstance逻辑较为简单,主要涉及FileConfiguration,load涉及Configuration代理
private static final String REGISTRY_CONF_DEFAULT = "registry";
private static final String ENV_SYSTEM_KEY = "SEATA_ENV";
public static final String ENV_PROPERTY_KEY = "seataEnv";
private static final String SYSTEM_PROPERTY_SEATA_CONFIG_NAME = "seata.config.name";
private static final String ENV_SEATA_CONFIG_NAME = "SEATA_CONFIG_NAME";
public static volatile Configuration CURRENT_FILE_INSTANCE;
public static volatile FileConfiguration ORIGIN_FILE_INSTANCE_REGISTRY;
public static volatile FileConfiguration ORIGIN_FILE_INSTANCE = null;
static {
// 负责初始化ORIGIN_FILE_INSTANCE_REGISTRY(FileConfiguration),通过读取registry.conf(<configName>-<envName>.conf)
initOriginConfiguration();
// 初始化CURRENT_FILE_INSTANCE(判断是否有extConfiguration,没有就用ORIGIN_FILE_INSTANCE_REGISTRY,本来FileConfiguration就是Configuration的实现)
// ext默认有个SpringBootConfigurationProvider实现,返回一个代理对象(seata-spring-autoconfigure-core里)
load();
// 如果CURRENT_FILE_INSTANCE是.conf的(也就是load用的还是registry.conf)
// 那原配置文件ORIGIN_FILE_INSTANCE就用的registry.conf里的config.file.name(test中给的file.conf)
maybeNeedOriginFileInstance();
}
FileConfiguration
继承自AbstractConfiguration,主要有两类方法和对应的两个内部类:
config相关方法: 对应内部类ConfigOperateRunnable,其中getLatestConfig是核心,AbstractConfiguration所有get方法都是调用的getLatestConfig,该方法优先找系统配置(System.getProperty),再异步获取本地文件配置(get方法会被下面的load()代理,导致优先走代理逻辑)。putConfig、removeConfig等方法目前还没实现,在ConfigOperateRunnable里都是todo。
listener相关方法:对应内部类FileListener,主要设置dataId对应的监听器,在file.listener.enabled为true时,每1000ms一次获取dataId的最新值。
SpringBootConfigurationProvider
对应load()方法。融入spring获取value的方式。主要是通过SPI去找ExtConfigurationProvider的实现然后调用provide方法,目前唯一提供的实现SpringBootConfigurationProvider,它是通过动态代理创建一个Configuration的代理对象,来拦截并设置get方法获取的值
public class SpringBootConfigurationProvider implements ExtConfigurationProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringBootConfigurationProvider.class);
private static final String INTERCEPT_METHOD_PREFIX = "get";
private static final Map<String, Object> PROPERTY_BEAN_INSTANCE_MAP = new ConcurrentHashMap<>(64);
@Override
public Configuration provide(Configuration originalConfiguration) {
return (Configuration)Enhancer.create(originalConfiguration.getClass(),
(MethodInterceptor)(proxy, method, args, methodProxy) -> {
if (method.getName().startsWith(INTERCEPT_METHOD_PREFIX) && args.length > 0) {
Object result;
String rawDataId = (String)args[0];
Class<?> dataType = ReflectionUtil.getWrappedClass(method.getReturnType());
// 1. Get config value from the system property
result = originalConfiguration.getConfigFromSys(rawDataId);
if (result == null) {
String dataId = convertDataId(rawDataId);
// 2. Get config value from the springboot environment
result = getConfigFromEnvironment(dataId, dataType);
if (result != null) {
return result;
}
// 3. Get config defaultValue from the arguments
if (args.length > 1) {
result = args[1];
if (result != null) {
// See Configuration#getConfig(String dataId, long timeoutMills)
if (dataType.isAssignableFrom(result.getClass())) {
return result;
} else {
result = null;
}
}
}
// 4. Get config defaultValue from the property object
try {
result = getDefaultValueFromPropertyObject(dataId);
} catch (Throwable t) {
LOGGER.error("Get config '{}' default value from the property object failed:", dataId, t);
}
}
if (result != null) {
if (dataType.isAssignableFrom(result.getClass())) {
return result;
}
// Convert type
return this.convertType(result, dataType);
}
}
return method.invoke(originalConfiguration, args);
});
}
...
}
Configuration的get方法拦截后,value取值优先级
result,也就是get方法的结果读取优先级:
1、环境变量(步骤1里getenv和getProperty)
2、ApplicationContext(步骤2里的ObjectHolder,很贴心的做了各种变换去找,下面会去看ObjectHolder怎么来的)
3、Configuration.getConfig(String dataId, String defaultValue…)(步骤3取默认值)
4、 从PROPERTY_BEAN_MAP获取(步骤4,下面会去看PROPERTY_BEAN_MAP怎么来的)
ObjectHolder
seata-spring-autoconfigure-core的spring.factories配了个自动配置项SeataCoreAutoConfiguration
PROPERTY_BEAN_MAP
同上,seata-spring-autoconfigure-core的spring.factories配了个自动配置项SeataCoreEnvironmentPostProcessor,并且client和server包里也配置了SeataClientEnvironmentPostProcessor和SeataServerEnvironmentPostProcessor
getInstance
buildConfiguration
reload
工作去了,晚点更