Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolved embedded value in annotation @ApolloConfigChangeListener #3349

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b801014
feat(apollo-client): use ConfigurableBeanFactory to resolve embedded …
Anilople Oct 23, 2020
6513539
test(apollo-client): resolve embedded value in ApolloConfigChangeList…
Anilople Oct 23, 2020
7823bda
docs(apollo-client): ApolloConfigChangeListener's embedded value usage
Anilople Oct 24, 2020
d5407cd
feat(apollo-client): resolve embedded value in '@ApolloConfig'
Anilople Nov 1, 2020
7bb0147
feat(apollo-client): resolve embedded value in '@EnableApolloConfig'
Anilople Nov 1, 2020
b096d8f
fix(apollo-client): implement BeanFactoryAware in ApolloConfigRegistrar
Anilople Nov 2, 2020
d5670b5
refactor(apollo-client): process annotation ApolloConfig
Anilople Nov 3, 2020
ac672e6
refactor(apollo-client): move '@ApolloJsonValue' processor
Anilople Nov 3, 2020
2e1616c
refactor(apollo-client): move field
Anilople Nov 3, 2020
66389c7
test(apollo-client): embedded value in '@EnableApolloConfig' cannot b…
Anilople Nov 4, 2020
ee934e3
feat(apollo-client): use Environment to resolve value in '@EnableApol…
Anilople Nov 6, 2020
cc1bbf7
test(apollo-client): '@EnableApolloConfig' resolving testing
Anilople Nov 6, 2020
bd3c5de
docs(apollo-client): ApolloConfigChangeListener usage
Anilople Nov 8, 2020
4170a99
docs(apollo-client): '@ApolloConfig' usage.
Anilople Nov 8, 2020
4c0e7de
docs(apollo-client): '@EnableApolloConfig' usage.
Anilople Nov 8, 2020
44d96bb
feat(apollo-client): use Environment to resolve placeholder
Anilople Nov 10, 2020
a8b029a
test(apollo-client): placeholder in '@ApolloConfig'
Anilople Nov 11, 2020
2f8ba8c
test(apollo-client): resolve placeholder in '@EnableApolloConfig'
Anilople Nov 11, 2020
cab3dfe
test(apollo-client): rename
Anilople Nov 11, 2020
936784a
docs(apollo-client): '@EnableApolloConfig' usage
Anilople Nov 11, 2020
60408cb
test(apollo-client): spy the return of prepareYamlConfigFile
Anilople Nov 11, 2020
b80b639
test(apollo-client): refactor the way to read file under src/test/res…
Anilople Nov 11, 2020
b847d86
test(apollo-client): resolve placeholder in '@ApolloConfigChangeListe…
Anilople Nov 11, 2020
0d5020f
test(apollo-client): refactor XmlConfigPlaceholderTest
Anilople Nov 11, 2020
7a6e3c2
feat(apollo-client): resolve placeholder in xml config #3367
Anilople Nov 11, 2020
9480b21
test(apollo-client): resolve placeholder in xml config #3367
Anilople Nov 11, 2020
eff0196
Merge branch 'master' into feature/embedded-value-in-ApolloConfigChan…
Anilople Nov 11, 2020
e23b852
docs(apollo-client): '@EnableApolloConfig' placeholder could not be c…
Anilople Nov 14, 2020
9c5f8d9
test(apollo-client): '@EnableApolloConfig' mock value to field for check
Anilople Nov 14, 2020
cd0491b
test(apollo-client): '@EnableApolloConfig' resolve placeholder from s…
Anilople Nov 14, 2020
138a50e
test(apollo-client): reset system propery after each test case
Anilople Nov 14, 2020
280ca0f
test(apollo-client): change the way to clear system propery.
Anilople Nov 14, 2020
a550b34
test(apollo-client): fix concurrent problem
Anilople Nov 14, 2020
1f3e6f4
test(apollo-client): change "someKey" to forbid confliction
Anilople Nov 14, 2020
2ff60d5
test(apollo-client): clear custom system property after each test case
Anilople Nov 22, 2020
363c727
test(apollo-client): delete unnecessary test case.
Anilople Nov 22, 2020
593ce02
test(apollo-client): delete redundant code in test case testApolloCon…
Anilople Nov 22, 2020
28e34e6
test(apollo-client): change assertEquals to assertSame to check mocke…
Anilople Nov 22, 2020
27c043d
test(apollo-client): clear system property after test
Anilople Nov 22, 2020
b5eb6f0
test(apollo-client): fix 'there is no value for xxx.from.system.prope…
Anilople Nov 22, 2020
de5ca86
Merge branch 'master' into feature/embedded-value-in-ApolloConfigChan…
Anilople Nov 22, 2020
f18b4f8
test(apollo-client): clear system property manually
Anilople Nov 22, 2020
c4f0665
Update JavaConfigAnnotationTest.java
nobodyiam Nov 22, 2020
811f42a
Update JavaConfigAnnotationTest.java
nobodyiam Nov 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
import java.util.Set;

import com.google.common.collect.Sets;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

Expand All @@ -18,7 +22,12 @@
*
* @author Jason Song(song_s@ctrip.com)
*/
public class ApolloAnnotationProcessor extends ApolloProcessor {
public class ApolloAnnotationProcessor extends ApolloProcessor implements BeanFactoryAware {

/**
* resolve the expression.
*/
private ConfigurableBeanFactory configurableBeanFactory;

@Override
protected void processField(Object bean, String beanName, Field field) {
Expand All @@ -30,15 +39,20 @@ protected void processField(Object bean, String beanName, Field field) {
Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()),
"Invalid type: %s for field: %s, should be Config", field.getType(), field);

String namespace = annotation.value();
Config config = ConfigService.getConfig(namespace);
final String namespace = annotation.value();
final String resolvedNamespace = this.configurableBeanFactory.resolveEmbeddedValue(namespace);
Config config = ConfigService.getConfig(resolvedNamespace);

ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, bean, config);
}

@Override
protected void processMethod(final Object bean, String beanName, final Method method) {
this.processApolloConfigChangeListener(bean, method);
}

private void processApolloConfigChangeListener(final Object bean, final Method method) {
ApolloConfigChangeListener annotation = AnnotationUtils
.findAnnotation(method, ApolloConfigChangeListener.class);
if (annotation == null) {
Expand Down Expand Up @@ -67,7 +81,7 @@ public void onChange(ConfigChangeEvent changeEvent) {
Set<String> interestedKeyPrefixes = annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) : null;

for (String namespace : namespaces) {
Config config = ConfigService.getConfig(namespace);
Config config = ConfigService.getConfig(this.configurableBeanFactory.resolveEmbeddedValue(namespace));

if (interestedKeys == null && interestedKeyPrefixes == null) {
config.addChangeListener(configChangeListener);
Expand All @@ -76,4 +90,9 @@ public void onChange(ConfigChangeEvent changeEvent) {
}
}
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
* //handle change event
* }
* <br />
* //Listener on namespace of "xxx" by default, or the namespace which value of key "redis.namespace" you specify.
Anilople marked this conversation as resolved.
Show resolved Hide resolved
* &#064;ApolloConfigChangeListener({"${redis.namespace:xxx}"})
* private void onChange(ConfigChangeEvent changeEvent) {
* //handle change event
* }
* <br />
* //Listener on namespaces of "someNamespace" and "anotherNamespace", will only be notified when "someKey" or "anotherKey" is changed
* &#064;ApolloConfigChangeListener(value = {"someNamespace","anotherNamespace"}, interestedKeys = {"someKey", "anotherKey"})
* private void onChange(ConfigChangeEvent changeEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,28 @@

import com.ctrip.framework.apollo.spring.spi.ApolloConfigRegistrarHelper;
import com.ctrip.framework.foundation.internals.ServiceBootstrap;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
* @author Jason Song(song_s@ctrip.com)
*/
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

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

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

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.helper.setBeanFactory(beanFactory);
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.ctrip.framework.apollo.spring.spi;

import com.ctrip.framework.apollo.core.spi.Ordered;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.type.AnnotationMetadata;

public interface ApolloConfigRegistrarHelper extends Ordered {
public interface ApolloConfigRegistrarHelper extends Ordered, BeanFactoryAware {
Anilople marked this conversation as resolved.
Show resolved Hide resolved

void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,29 @@
import com.google.common.collect.Lists;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;

public class DefaultApolloConfigRegistrarHelper implements ApolloConfigRegistrarHelper {

/**
* resolve the expression.
*/
private ConfigurableBeanFactory configurableBeanFactory;

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
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);
final String[] namespaces = attributes.getStringArray("value");
final int order = attributes.getNumber("order");
final String[] resolvedNamespaces = this.resolveNamespaces(namespaces);
PropertySourcesProcessor.addNamespaces(Lists.newArrayList(resolvedNamespaces), order);

Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
// to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
Expand All @@ -44,8 +53,22 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
ApolloJsonValueProcessor.class);
}

private String[] resolveNamespaces(String[] namespaces) {
String[] resolvedNamespaces = new String[namespaces.length];
for (int i = 0; i < namespaces.length; i++) {
resolvedNamespaces[i] = this.configurableBeanFactory.resolveEmbeddedValue(namespaces[i]);
Anilople marked this conversation as resolved.
Show resolved Hide resolved
}
return resolvedNamespaces;
}

@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.ctrip.framework.apollo.spring;

import static org.mockito.Mockito.mock;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
import java.util.Properties;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;

public class JavaConfigAnnotationApolloConfigChangeListenerTest extends
Anilople marked this conversation as resolved.
Show resolved Hide resolved
AbstractSpringIntegrationTest {

@Test
public void testResolveExpressionSimple() {
Config applicationConfig = mock(Config.class);
mockConfig("application", applicationConfig);
new AnnotationConfigApplicationContext(TestResolveExpressionSimpleConfiguration.class);
Anilople marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* resolve namespace's name from system property.
*/
@Test
public void testResolveExpressionFromSystemProperty() {
Config applicationConfig = mock(Config.class);
mockConfig(ConfigConsts.NAMESPACE_APPLICATION, applicationConfig);

final String namespaceName = "magicRedis";
System.setProperty("redis.namespace", namespaceName);
Config redisConfig = mock(Config.class);
mockConfig(namespaceName, redisConfig);
new AnnotationConfigApplicationContext(
TestResolveExpressionFromSystemPropertyConfiguration.class);
Anilople marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* resolve namespace from config. ${mysql.namespace} will be resolved by config from namespace
* application.
*/
@Test
public void testResolveExpressionFromApplicationNamespace() {
Config applicationConfig = mock(Config.class);
mockConfig(ConfigConsts.NAMESPACE_APPLICATION, applicationConfig);

final String namespaceKey = "mysql.namespace";
final String namespaceName = "magicMysqlNamespaceApplication";

Properties properties = new Properties();
properties.setProperty(namespaceKey, namespaceName);
this.prepareConfig(ConfigConsts.NAMESPACE_APPLICATION, properties);

Config mysqlConfig = mock(Config.class);
mockConfig(namespaceName, mysqlConfig);

new AnnotationConfigApplicationContext(
TestResolveExpressionFromApplicationNamespaceConfiguration.class);
Anilople marked this conversation as resolved.
Show resolved Hide resolved
}

@Configuration
@EnableApolloConfig
static class TestResolveExpressionSimpleConfiguration {

@ApolloConfigChangeListener("${simple.application:application}")
private void onChange(ConfigChangeEvent event) {
}
}

@Configuration
@EnableApolloConfig
static class TestResolveExpressionFromSystemPropertyConfiguration {

@ApolloConfigChangeListener(value = {ConfigConsts.NAMESPACE_APPLICATION,
"${redis.namespace}"})
private void onChange(ConfigChangeEvent event) {
}
}

@Configuration
@EnableApolloConfig
static class TestResolveExpressionFromApplicationNamespaceConfiguration {

@ApolloConfigChangeListener(value = {ConfigConsts.NAMESPACE_APPLICATION,
"${mysql.namespace}"})
private void onChange(ConfigChangeEvent event) {
}
}
}