apollo--集成spring

启动过程

启动过程

"

UML

Spring

"

XML配置

NamespaceHandler

com.ctrip.framework.apollo.spring.config.NamespaceHandler ,实现 org.springframework.beans.factory.xml.NamespaceHandlerSupport 抽象类,Apollo 的 XML Namespace 的处理器。

如下是apollo namespace的xml配置:

1
2
3
4
<!-- 这个是最简单的配置形式,一般应用用这种形式就可以了,用来指示Apollo注入application namespace的配置到Spring环境中 -->
<apollo:config/>
<!-- 这个是稍微复杂一些的配置形式,指示Apollo注入FX.apollo和FX.soa namespace的配置到Spring环境中 -->
<apollo:config namespaces="FX.apollo,FX.soa"/>

NamespaceHandler把每一个带有config标签的元素解析成ConfigPropertySourcesProcessor类型的bean,由spring管理,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class NamespaceHandler extends NamespaceHandlerSupport {
private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();

@Override
public void init() {
registerBeanDefinitionParser("config", new BeanParser());
}

static class BeanParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
// config 标签被解析成 ConfigPropertySourcesProcessor对象
return ConfigPropertySourcesProcessor.class;
}

@Override
protected boolean shouldGenerateId() {
// 为每个bean自动生成一个id
return true;
}

@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
// 解析 `namespaces` 属性,默认为 `"application"`
String namespaces = element.getAttribute("namespaces");
if (Strings.isNullOrEmpty(namespaces)) {
namespaces = ConfigConsts.NAMESPACE_APPLICATION;
}

// 解析 `order` 属性,默认为 Ordered.LOWEST_PRECEDENCE;
int order = Ordered.LOWEST_PRECEDENCE;
String orderAttribute = element.getAttribute("order");

if (!Strings.isNullOrEmpty(orderAttribute)) {
try {
order = Integer.parseInt(orderAttribute);
} catch (Throwable ex) {
throw new IllegalArgumentException(
String.format("Invalid order: %s for namespaces: %s", orderAttribute, namespaces));
}
}

// 添加到 PropertySourcesProcessor
PropertySourcesProcessor.addNamespaces(NAMESPACE_SPLITTER.splitToList(namespaces), order);
}
}
}

// PropertySourcesProcessor的静态方法addNamespaces
private static final Multimap<Integer, String> NAMESPACE_NAMES = LinkedHashMultimap.create();
public static boolean addNamespaces(Collection<String> namespaces, int order) {
return NAMESPACE_NAMES.putAll(order, namespaces);
}

ConfigPropertySourcesProcessor

com.ctrip.framework.apollo.spring.config.ConfigPropertySourcesProcessor ,实现BeanDefinitionRegistryPostProcessor 接口,继承 PropertySourcesProcessor 类,Apollo PropertySource 处理器。

Apollo Property Sources processor for Spring XML Based Application

1
2
3
4
5
6
7
8
9
10
public class ConfigPropertySourcesProcessor extends PropertySourcesProcessor
implements BeanDefinitionRegistryPostProcessor {

private ConfigPropertySourcesProcessorHelper helper = ServiceBootstrap.loadPrimary(ConfigPropertySourcesProcessorHelper.class);

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
helper.postProcessBeanDefinitionRegistry(registry);
}
}

postProcessBeanDefinitionRegistry

postProcessBeanDefinitionRegistry阶段,DefaultConfigPropertySourcesProcessorHelper注册一些BeanDefinitionBeanDefinitionRegistry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
// to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
propertySourcesPlaceholderPropertyValues.put("order", 0);

// 注册 PropertySourcesPlaceholderConfigurer 到 BeanDefinitionRegistry 中,替换 PlaceHolder 为对应的属性值
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
// 注册 ApolloAnnotationProcessor 到 BeanDefinitionRegistry 中,因为 XML 配置的 Bean 对象,也可能存在 @ApolloConfig 和 @ApolloConfigChangeListener 注解。
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
ApolloAnnotationProcessor.class);
// 注册 SpringValueProcessor 到 BeanDefinitionRegistry 中,用于 PlaceHolder 自动更新机制
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(),
SpringValueProcessor.class);
// 注册 ApolloJsonValueProcessor 到 BeanDefinitionRegistry 中,因为 XML 配置的 Bean 对象,也可能存在 @ApolloJsonValue 注解。
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
ApolloJsonValueProcessor.class);

// 处理 XML 配置的 Spring PlaceHolder
processSpringValueDefinition(registry);
}

/**
* For Spring 3.x versions, the BeanDefinitionRegistryPostProcessor would not be instantiated if
* it is added in postProcessBeanDefinitionRegistry phase, so we have to manually call the
* postProcessBeanDefinitionRegistry method of SpringValueDefinitionProcessor here...
*
即:
在 Spring 3.x 版本中,BeanDefinitionRegistryPostProcessor ( SpringValueDefinitionProcessor 实现了该接口 )无法 在 postProcessBeanDefinitionRegistry 阶段被实例化,因此,我们不得不手动创建 SpringValueDefinitionProcessor 对 象,并调用其 #postProcessBeanDefinitionRegistry(BeanDefinitionRegistry) 方法。
*/
private void processSpringValueDefinition(BeanDefinitionRegistry registry) {
SpringValueDefinitionProcessor springValueDefinitionProcessor = new SpringValueDefinitionProcessor();

springValueDefinitionProcessor.postProcessBeanDefinitionRegistry(registry);
}

Apollo 为了实现自动更新机制,做了很多处理,重点在于找到 XML 和注解配置的 PlaceHolder,全部以 StringValue的形式,注册到 SpringValueRegistry中,从而让 AutoUpdateConfigChangeListener 监听到 Apollo 配置变更后,能够从 SpringValueRegistry中找到发生属性值变更的属性对应的 StringValue ,进行修改。

SpringValueDefinitionProcessor

com.ctrip.framework.apollo.spring.property.SpringValueDefinitionProcessor ,实现 BeanDefinitionRegistryPostProcessor 接口,处理 Spring XML PlaceHolder ,解析成 StringValueDefinition 集合

SpringValueDefinition

1
2
3
4
<bean class="com.ctrip.framework.apollo.demo.spring.xmlConfigDemo.bean.XmlBean">    
<property name="timeout" value="${timeout:200}"/>
<property name="batch" value="${batch:100}"/>
</bean>

每个 <property /> 都会被解析成一个 StringValueDefinition 对象。

1
2
3
4
5
6
7
8
public class SpringValueDefinition {
// Key,即在Config中配置的key
private final String key;
// 占位符
private final String placeholder;
// 属性名
private final String propertyName;
}

eg: name值: timeout映射成propertyName,value值:${timeout:200}映射成placeholder,timeout映射成key

postProcessBeanDefinitionRegistry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
private static final Map<BeanDefinitionRegistry, Multimap<String, SpringValueDefinition>> beanName2SpringValueDefinitions =
Maps.newConcurrentMap();
private static final Set<BeanDefinitionRegistry> PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet();

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 是否开启自动更新功能,因为 SpringValueDefinitionProcessor 就是为了这个功能编写的。默认true
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
processPropertyValues(registry);
}
}

private void processPropertyValues(BeanDefinitionRegistry beanRegistry) {
if (!PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES.add(beanRegistry)) {
// already initialized
return;
}

if (!beanName2SpringValueDefinitions.containsKey(beanRegistry)) {
beanName2SpringValueDefinitions.put(beanRegistry, LinkedListMultimap.<String, SpringValueDefinition>create());
}

Multimap<String, SpringValueDefinition> springValueDefinitions = beanName2SpringValueDefinitions.get(beanRegistry);

String[] beanNames = beanRegistry.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName);
// 获取beanDefinition的属性
MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues();
List<PropertyValue> propertyValues = mutablePropertyValues.getPropertyValueList();
// 循环 BeanDefinition 的 PropertyValue 数组
for (PropertyValue propertyValue : propertyValues) {
Object value = propertyValue.getValue();
// 忽略非 字符串类型的 属性。
if (!(value instanceof TypedStringValue)) {
continue;
}
String placeholder = ((TypedStringValue) value).getValue();
// 提取 `keys` 属性们。
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
// 如果提取出来的keys为空,说明当前值没有使用占位符
if (keys.isEmpty()) {
continue;
}

for (String key : keys) {
// 占位符中的每个key,都封装成一个SpringValueDefinition对象,并添加到 `beanName2SpringValueDefinitions` 中
springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName()));
}
}
}
}

PlaceholderHelper#extractPlaceholderKeys(placeholder) 方法,为什么会提取到多个 key 属性呢?

Extract keys from placeholder, e.g.

  • ${some.key} => “some.key”
  • ${some.key:${some.other.key:100}} => “some.key”, “some.other.key”
  • ${${some.key}} => “some.key”
  • ${${some.key:other.key}} => “some.key”
  • ${${some.key}:${another.key}} => “some.key”, “another.key”
  • #{new java.text.SimpleDateFormat('${some.key}').parse('${another.key}')} => “some.key”, “another.key”

PropertySourcesProcessor

com.ctrip.framework.apollo.spring.config.PropertySourcesProcessor , 实现 BeanFactoryPostProcessor、EnvironmentAware、PriorityOrdered 接口,PropertySource 处理器。同时也是ConfigPropertySourcesProcessor的父类。

postProcessBeanFactory

实现 BeanFactoryPostProcessor 接口,可以在 spring 的 bean 创建之前,修改 bean 的定义属性。也就是说,Spring 允许 BeanFactoryPostProcessor 在容器实例化任何其它bean 之前读取配置元数据,并可以根据需要进行修改,例如可以把 bean 的 scope 从 singleton 改为 prototype ,也可以把 property 的值给修改掉。可以同时配置多个BeanFactoryPostProcessor ,并通过设置 order 属性来控制各个BeanFactoryPostProcessor 的执行次序

注意:BeanFactoryPostProcessor 是在 spring 容器加载了 bean 的定义文件之后,在 bean 实例化之前执行的

#postProcessBeanFactory(ConfigurableListableBeanFactory) 方法,代码如下:

1
2
3
4
5
6
7
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 初始化PropertySource,并设置到environment中,使bean可以读取到apollo的配置
initializePropertySources();
// 初始化 AutoUpdateConfigChangeListener 对象,实现属性的自动更新
initializeAutoUpdatePropertiesFeature(beanFactory);
}
初始化PropertySource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
private void initializePropertySources() {
// 若 `environment` 已经有 APOLLO_PROPERTY_SOURCE_NAME 属性源,说明已经初始化,直接返回。
if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME)) {
//already initialized
return;
}
// 创建 CompositePropertySource 对象,组合多个 Namespace 的 ConfigPropertySource 。
CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME);

// 按照优先级,顺序遍历 Namespace
ImmutableSortedSet<Integer> orders = ImmutableSortedSet.copyOf(NAMESPACE_NAMES.keySet());
Iterator<Integer> iterator = orders.iterator();

while (iterator.hasNext()) {
int order = iterator.next();
for (String namespace : NAMESPACE_NAMES.get(order)) {
Config config = ConfigService.getConfig(namespace);
// 创建 Namespace 对应的 ConfigPropertySource 对象,添加到 `composite` 中。
composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
}
}

// clean up
NAMESPACE_NAMES.clear();

// 添加到environment的PropertySources属性中
// add after the bootstrap property source or to the first
if (environment.getPropertySources()
.contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {

// ensure ApolloBootstrapPropertySources is still the first
ensureBootstrapPropertyPrecedence(environment);

environment.getPropertySources()
.addAfter(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME, composite);
} else {
environment.getPropertySources().addFirst(composite);
}
}

// ConfigPropertySource 工厂
public class ConfigPropertySourceFactory {

/**
* ConfigPropertySource 数组
*/
private final List<ConfigPropertySource> configPropertySources = Lists.newLinkedList();

// 创建 ConfigPropertySource 对象
public ConfigPropertySource getConfigPropertySource(String name, Config source) {
// 创建 ConfigPropertySource 对象
ConfigPropertySource configPropertySource = new ConfigPropertySource(name, source);
// 添加到数组中
configPropertySources.add(configPropertySource);
return configPropertySource;
}

public List<ConfigPropertySource> getAllConfigPropertySources() {
return Lists.newLinkedList(configPropertySources);
}
}

// 实现 org.springframework.core.env.ConfigPropertySource 抽象类,基于 Apollo Config 的 PropertySource 实现类
public class ConfigPropertySource extends EnumerablePropertySource<Config> {
private static final String[] EMPTY_ARRAY = new String[0];
ConfigPropertySource(String name, Config source) {
// 此处的 Apollo Config 作为 `source`
super(name, source);
}

@Override
public String[] getPropertyNames() {
// 从 Config 中,获得属性名集合
Set<String> propertyNames = this.source.getPropertyNames();
// 转换成 String 数组,返回
if (propertyNames.isEmpty()) {
return EMPTY_ARRAY;
}
return propertyNames.toArray(new String[0]);
}

@Override
public Object getProperty(String name) {
return this.source.getProperty(name, null);
}

/**
* 添加 ConfigChangeListener 到 Config 中
*
* @param listener 监听器
*/
public void addChangeListener(ConfigChangeListener listener) {
this.source.addChangeListener(listener);
}

}
初始化AutoUpdateConfigChangeListener

调用 #initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory) 方法,初始化 AutoUpdateConfigChangeListener 对象,实现 Spring Placeholder 的自动更新功能。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) {
// 若未开启属性的自动更新功能,直接返回;默认开启
if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() ||
!AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES.add(beanFactory)) {
return;
}

// 创建 AutoUpdateConfigChangeListener 对象
AutoUpdateConfigChangeListener autoUpdateConfigChangeListener = new AutoUpdateConfigChangeListener(
environment, beanFactory);

// 向 每个ConfigPropertySource 注册监听事件
List<ConfigPropertySource> configPropertySources = configPropertySourceFactory.getAllConfigPropertySources();
for (ConfigPropertySource configPropertySource : configPropertySources) {
configPropertySource.addChangeListener(autoUpdateConfigChangeListener);
}
}

ApolloProcessor

com.ctrip.framework.apollo.spring.annotation.ApolloProcessor ,实现 BeanPostProcessor、PriorityOrdered 接口,Apollo 处理器抽象类,封装了在 Spring Bean 初始化之前,处理属性和方法。但是具体的处理,是两个抽象方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public abstract class ApolloProcessor implements BeanPostProcessor, PriorityOrdered {

// 在bean初始化前处理bean的属性和方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Class clazz = bean.getClass();
for (Field field : findAllField(clazz)) {
processField(bean, beanName, field);
}
for (Method method : findAllMethod(clazz)) {
processMethod(bean, beanName, method);
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

/**
* subclass should implement this method to process field
*/
protected abstract void processField(Object bean, String beanName, Field field);

/**
* subclass should implement this method to process method
*/
protected abstract void processMethod(Object bean, String beanName, Method method);
......省略部分代码........
}

ApolloProcessor 有三个子类实现:

  • SpringValueProcessor
  • ApolloAnnotationProcessor
  • ApolloJsonValueProcessor

SpringValueProcessor

com.ctrip.framework.apollo.spring.annotation.SpringValueProcessor ,实现 BeanFactoryPostProcessor 接口,继承 ApolloProcessor 抽象类,Spring Value 处理器,处理:

  1. 带有 @Value 注解的 Field 和 Method
  2. XML 配置的 Bean 的 PlaceHolder 们

每个 Field、Method、XML PlaceHolder 被处理成一个 SpringValue 对象,添加到 SpringValueRegistry 中。
目的还是,为了 PlaceHolder 的自动更新机制。

SpringValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class SpringValue {
// Spring 方法参数封装
private MethodParameter methodParameter;
// Field
private Field field;
// Bean 对象
private WeakReference<Object> beanRef;
// Bean 名字
private String beanName;
// KEY:即在 Config 中的属性 KEY 。
private String key;
// 占位符
private String placeholder;
// 值类型
private Class<?> targetType;
// 泛型。当是 JSON 类型时,使用
private Type genericType;
// 是否 JSON
private boolean isJson;

// 通过反射,update value
public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
// Field
if (isField()) {
injectField(newVal);
// Method
} else {
injectMethod(newVal);
}
}

private void injectField(Object newVal) throws IllegalAccessException {
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(bean, newVal);
field.setAccessible(accessible);
}

private void injectMethod(Object newVal) throws InvocationTargetException, IllegalAccessException {
methodParameter.getMethod().invoke(bean, newVal);
}
}

SpringValueRegistry

SpringValue 注册表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class SpringValueRegistry {
private static final long CLEAN_INTERVAL_IN_SECONDS = 5;
private final Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();
private final AtomicBoolean initialized = new AtomicBoolean(false);

public void register(BeanFactory beanFactory, String key, SpringValue springValue) {
....省略...
registry.get(beanFactory).put(key, springValue);

// lazy initialize
if (initialized.compareAndSet(false, true)) {
initialize();
}
}

private void initialize() {
// 初始化清理回收bean的定时器
Executors.newSingleThreadScheduledExecutor(ApolloThreadFactory.create("SpringValueRegistry", true)).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
try {
scanAndClean();
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS);
}

private void scanAndClean() {
Iterator<Multimap<String, SpringValue>> iterator = registry.values().iterator();
while (!Thread.currentThread().isInterrupted() && iterator.hasNext()) {
Multimap<String, SpringValue> springValues = iterator.next();
Iterator<Entry<String, SpringValue>> springValueIterator = springValues.entries().iterator();
while (springValueIterator.hasNext()) {
Entry<String, SpringValue> springValue = springValueIterator.next();
// 如果bean被垃圾回收,从注册表中删除
if (!springValue.getValue().isTargetBeanValid()) {
// clear unused spring values
springValueIterator.remove();
}
}
}
}
}

postProcessBeanFactory

1
2
3
4
5
6
7
8
9
10
private Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
// 是否开启自动更新机制
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && beanFactory instanceof BeanDefinitionRegistry) {
// 获取xml中的PlaceHolder:获取SpringValueDefinitionProcessor解析过的SpringValueDefinition
beanName2SpringValueDefinitions = SpringValueDefinitionProcessor
.getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory);
}
}

SpringValueDefinitionProcessor的执行在postProcessBeanDefinitionRegistry阶段;SpringValueProcessor执行在postProcessBeanFactory阶段。SpringValueDefinitionProcessor执行在SpringValueProcessor前面。

postProcessBeforeInitialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// 是否开启自动更新
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
// 处理 java annotation配置的PlaceHolder:Field 和 Method 上的@value注解
super.postProcessBeforeInitialization(bean, beanName);
// 处理 XML 配置的 Bean 的 PlaceHolder
processBeanPropertyValues(bean, beanName);
}
return bean;
}

// 处理 XML 配置的 Bean 的 PlaceHolder
private void processBeanPropertyValues(Object bean, String beanName) {
// 获得 SpringValueDefinition 数组
Collection<SpringValueDefinition> propertySpringValues = beanName2SpringValueDefinitions
.get(beanName);
if (propertySpringValues == null || propertySpringValues.isEmpty()) {
return;
}

// 循环 SpringValueDefinition 数组,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
for (SpringValueDefinition definition : propertySpringValues) {
try {
PropertyDescriptor pd = BeanUtils
.getPropertyDescriptor(bean.getClass(), definition.getPropertyName());
Method method = pd.getWriteMethod();
if (method == null) {
continue;
}
// 创建对应的 SpringValue 对象
SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(),
bean, beanName, method, false);
// 添加到 `springValueRegistry` 中
springValueRegistry.register(beanFactory, definition.getKey(), springValue);
logger.debug("Monitoring {}", springValue);
} catch (Throwable ex) {
logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(),
definition.getPropertyName());
}
}

// clear
beanName2SpringValueDefinitions.removeAll(beanName);
}

processField

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
protected void processField(Object bean, String beanName, Field field) {
// register @Value on field
Value value = field.getAnnotation(Value.class);
if (value == null) {
return;
}
Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());

if (keys.isEmpty()) {
return;
}

// 循环 `keys` ,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue);
}
}

processMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
protected void processMethod(Object bean, String beanName, Method method) {
//register @Value on method
Value value = method.getAnnotation(Value.class);
if (value == null) {
return;
}
// 忽略 @Bean 注解的方法
if (method.getAnnotation(Bean.class) != null) {
return;
}

if (method.getParameterTypes().length != 1) {
logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters",
bean.getClass().getName(), method.getName(), method.getParameterTypes().length);
return;
}

Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());

if (keys.isEmpty()) {
return;
}

// 循环 `keys` ,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
springValueRegistry.register(beanFactory, key, springValue);
logger.info("Monitoring {}", springValue);
}
}

AutoUpdateConfigChangeListener

com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener ,实现 ConfigChangeListener 接口,自动更新配置监听器

onChange

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void onChange(ConfigChangeEvent changeEvent) {
Set<String> keys = changeEvent.changedKeys();
if (CollectionUtils.isEmpty(keys)) {
return;
}
for (String key : keys) {
// 1. check whether the changed key is relevant
Collection<SpringValue> targetValues = springValueRegistry.get(beanFactory, key);
if (targetValues == null || targetValues.isEmpty()) {
continue;
}

// 2. update the value
for (SpringValue val : targetValues) {
updateSpringValue(val);
}
}
}

updateSpringValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private void updateSpringValue(SpringValue springValue) {
try {
// 获取最新值,并把值转换成需要的类型
Object value = resolvePropertyValue(springValue);
// 更新值
springValue.update(value);

logger.info("Auto update apollo changed value successfully, new value: {}, {}", value,
springValue);
} catch (Throwable ex) {
logger.error("Auto update apollo changed value failed, {}", springValue.toString(), ex);
}
}

private Object resolvePropertyValue(SpringValue springValue) {
// 解析PlaceHolder对应的最新值
Object value = placeholderHelper
.resolvePropertyValue(beanFactory, springValue.getBeanName(), springValue.getPlaceholder());

if (springValue.isJson()) {
// 如果值数据结构是 JSON 类型,则使用 Gson 解析成对应值的类型
value = parseJsonValue((String)value, springValue.getGenericType());
} else {
// 转换成需要的类型
// 1. 如果类型为 Field
if (springValue.isField()) {
// org.springframework.beans.TypeConverter#convertIfNecessary(java.lang.Object, java.lang.Class, java.lang.reflect.Field) is available from Spring 3.2.0+
if (typeConverterHasConvertIfNecessaryWithFieldParameter) {
value = this.typeConverter
.convertIfNecessary(value, springValue.getTargetType(), springValue.getField());
} else {
value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType());
}
} else {
// 2. 如果类型为 Method
value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(),
springValue.getMethodParameter());
}
}

return value;
}

java配置

@EnableApolloConfig

com.ctrip.framework.apollo.spring.annotation.@EnableApolloConfig 注解,可以使用它声明使用的 Apollo Namespace ,和 Apollo XML 配置的 <apollo:config /> 等价。

1
2
3
4
5
6
7
8
9
10
11
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ApolloConfigRegistrar.class)
public @interface EnableApolloConfig {
/**
* Apollo namespaces to inject configuration into Spring Property Sources.
*/
String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};
int order() default Ordered.LOWEST_PRECEDENCE;
}

ApolloConfigRegistrar

com.ctrip.framework.apollo.spring.annotation.ApolloConfigRegistrar ,实现 ImportBeanDefinitionRegistrar 接口,Apollo Spring Java Config 注册器。

ImportBeanDefinitionRegistrar:Spring官方在动态注册bean时,大部分套路其实是使用ImportBeanDefinitionRegistrar接口。所有实现了该接口的类的都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中动态注册的bean是优先与依赖其的bean初始化的,也能被aop、validator等机制处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {

private ApolloConfigRegistrarHelper helper = ServiceBootstrap.loadPrimary(ApolloConfigRegistrarHelper.class);

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
helper.registerBeanDefinitions(importingClassMetadata, registry);
}
}

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 解析 @EnableApolloConfig 注解,并把解析的namespace添加到PropertySourcesProcessor
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(EnableApolloConfig.class.getName()));
String[] namespaces = attributes.getStringArray("value");
int order = attributes.getNumber("order");
PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order);

Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
// to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
propertySourcesPlaceholderPropertyValues.put("order", 0);

// 注册 PropertySourcesPlaceholderConfigurer 到 BeanDefinitionRegistry 中,替换 PlaceHolder 为对应的属性值
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
// 注册 PropertySourcesProcessor 到 BeanDefinitionRegistry 中,因为可能存在 XML 配置的 Bean ,用于 PlaceHolder 自动更新机制
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
PropertySourcesProcessor.class);
// 注册 ApolloAnnotationProcessor 到 BeanDefinitionRegistry 中,解析 @ApolloConfig 和 @ApolloConfigChangeListener 注解。
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
ApolloAnnotationProcessor.class);
// 注册 SpringValueProcessor 到 BeanDefinitionRegistry 中,用于 PlaceHolder 自动更新机制
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(),
SpringValueProcessor.class);
// 注册 SpringValueDefinitionProcessor 到 BeanDefinitionRegistry 中,因为可能存在 XML 配置的 Bean ,用于 PlaceHolder 自动更新机制
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(),
SpringValueDefinitionProcessor.class);
// 注册 ApolloJsonValueProcessor 到 BeanDefinitionRegistry 中,解析 @ApolloJsonValue 注解。
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
ApolloJsonValueProcessor.class);
}

其他Annotation

@ApolloJsonValue

com.ctrip.framework.apollo.spring.annotation.@ApolloJsonValue 注解,将 Apollo 的一个 JSON 格式的属性进行注入,例如:

1
2
3
4
5
// Inject the json property value for type SomeObject.
// Suppose SomeObject has 2 properties, someString and someInt, then the possible config
// in Apollo is someJsonPropertyKey={"someString":"someValue", "someInt":10}.
@ApolloJsonValue("${someJsonPropertyKey:someDefaultValue}")
private SomeObject someObject;

将 Apollo 任意格式的 Namespace 的一个 Item 配置项,解析成对应类型的对象,注入到 @ApolloJsonValue 的对象中。

@ApolloConfig

com.ctrip.framework.apollo.spring.annotation.@ApolloConfig 注解,将 Apollo Config 对象注入,例如:

1
2
3
// Inject the config for "someNamespace"
@ApolloConfig("someNamespace")
private Config config;

@ApolloConfigChangeListener

com.ctrip.framework.apollo.spring.annotation.@ApolloConfigChangeListener 注解,将被注解的方法,向指定的 Apollo Config 发起配置变更监听,例如:

1
2
3
4
5
// Listener on namespaces of "someNamespace" and "anotherNamespace"
@ApolloConfigChangeListener({"someNamespace","anotherNamespace"})
private void onChange(ConfigChangeEvent changeEvent) {
// handle change event
}

其他配置

使用上述两种方式的配置形式( 基于 XML 的配置和基于Java的配置 )后,Apollo 会在 Spring 的 postProcessBeanFactory 阶段注入配置到 Spring 的 Environment中,早于 bean 的初始化阶段,所以对于普通的 bean 注入配置场景已经能很好的满足。

不过 Spring Boot 有一些场景需要配置在更早的阶段注入,比如使用 @ConditionalOnProperty 的场景或者是有一些 spring-boot-starter 在启动阶段就需要读取配置做一些事情( 如 spring-boot-starter-dubbo ),所以对于 Spring Boot 环境建议通过以下方式来接入 Apollo ( 需要0.10.0及以上版本 )。
使用方式很简单,只需要在 application.properties/bootstrap.properties 中按照如下样例配置即可。

1、在 bootstrap 阶段注入默认 "application" namespace 的配置示例:

1
2
3
 
# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true

2、在 bootstrap 阶段注入非默认 "application" namespace 或多个 namespace 的配置示例

1
2
3
apollo.bootstrap.enabled = true
# will inject 'application' and 'FX.apollo' namespaces in bootstrap phase
apollo.bootstrap.namespaces = application,FX.apollo

下面,让我们来看看具体的代码实现。
spring.factories
Apollo 在 apollo-clientMETA-INF/spring.factories定义如下:

1
2
3
4
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration
org.springframework.context.ApplicationContextInitializer=\
com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer

ApolloAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
@Configuration
// String APOLLO_BOOTSTRAP_ENABLED = "apollo.bootstrap.enabled";
@ConditionalOnProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED)
@ConditionalOnMissingBean(PropertySourcesProcessor.class)
public class ApolloAutoConfiguration {

@Bean
public ConfigPropertySourcesProcessor configPropertySourcesProcessor() {
return new ConfigPropertySourcesProcessor();
}
}

ApolloApplicationContextInitializer

com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer ,实现 ApplicationContextInitializer 接口,在 Spring Boot 启动阶段( bootstrap phase ),注入配置的 Apollo Config 对象们。

实现代码上,和 PropertySourcesProcessor 一样实现了注入配置的 Apollo Config 对象们,差别在于处于 Spring 的不同阶段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();

// 获得 "apollo.bootstrap.enabled" 配置项
if (!environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, Boolean.class, false)) {
logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED);
return;
}
logger.debug("Apollo bootstrap config is enabled for context {}", context);

initialize(environment);
}

protected void initialize(ConfigurableEnvironment environment) {

// 若已经有 APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME 的 PropertySource,就不再加载配置
if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
//already initialized
return;
}

// 获得 "apollo.bootstrap.namespaces" 配置项
String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);
logger.debug("Apollo bootstrap namespaces: {}", namespaces);
List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);

CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
// 按照优先级,顺序遍历 Namespace
for (String namespace : namespaceList) {
Config config = ConfigService.getConfig(namespace);
// 创建 Namespace 对应的 ConfigPropertySource 对象,添加到 `composite` 中。
composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
}

environment.getPropertySources().addFirst(composite);
}

备注

apollo 源码分析