forked from apolloconfig/apollo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support configuring namespaces as placeholders
- Loading branch information
Showing
16 changed files
with
711 additions
and
200 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,25 +3,73 @@ | |
import com.ctrip.framework.apollo.Config; | ||
import com.ctrip.framework.apollo.ConfigChangeListener; | ||
import com.ctrip.framework.apollo.ConfigService; | ||
import com.ctrip.framework.apollo.build.ApolloInjector; | ||
import com.ctrip.framework.apollo.model.ConfigChangeEvent; | ||
import com.ctrip.framework.apollo.spring.property.PlaceholderHelper; | ||
import com.ctrip.framework.apollo.spring.property.SpringValue; | ||
import com.ctrip.framework.apollo.spring.property.SpringValueRegistry; | ||
import com.ctrip.framework.apollo.spring.util.SpringInjector; | ||
import com.ctrip.framework.apollo.util.ConfigUtil; | ||
import com.google.common.base.Preconditions; | ||
import com.google.gson.Gson; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Type; | ||
import java.util.Set; | ||
|
||
import com.google.common.collect.Sets; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
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.context.EnvironmentAware; | ||
import org.springframework.core.annotation.AnnotationUtils; | ||
import org.springframework.core.env.Environment; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
/** | ||
* Apollo Annotation Processor for Spring Application | ||
* | ||
* @author Jason Song([email protected]) | ||
*/ | ||
public class ApolloAnnotationProcessor extends ApolloProcessor { | ||
public class ApolloAnnotationProcessor extends ApolloProcessor implements BeanFactoryAware, | ||
EnvironmentAware { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(ApolloAnnotationProcessor.class); | ||
private static final Gson GSON = new Gson(); | ||
|
||
private final ConfigUtil configUtil; | ||
private final PlaceholderHelper placeholderHelper; | ||
private final SpringValueRegistry springValueRegistry; | ||
|
||
/** | ||
* resolve the expression. | ||
*/ | ||
private ConfigurableBeanFactory configurableBeanFactory; | ||
|
||
private Environment environment; | ||
|
||
public ApolloAnnotationProcessor() { | ||
configUtil = ApolloInjector.getInstance(ConfigUtil.class); | ||
placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); | ||
springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); | ||
} | ||
|
||
@Override | ||
protected void processField(Object bean, String beanName, Field field) { | ||
this.processApolloConfig(bean, field); | ||
this.processApolloJsonValue(bean, beanName, field); | ||
} | ||
|
||
@Override | ||
protected void processMethod(final Object bean, String beanName, final Method method) { | ||
this.processApolloConfigChangeListener(bean, method); | ||
this.processApolloJsonValue(bean, beanName, method); | ||
} | ||
|
||
private void processApolloConfig(Object bean, Field field) { | ||
ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class); | ||
if (annotation == null) { | ||
return; | ||
|
@@ -30,15 +78,15 @@ 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.environment.resolveRequiredPlaceholders(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) { | ||
private void processApolloConfigChangeListener(final Object bean, final Method method) { | ||
ApolloConfigChangeListener annotation = AnnotationUtils | ||
.findAnnotation(method, ApolloConfigChangeListener.class); | ||
if (annotation == null) { | ||
|
@@ -63,11 +111,15 @@ public void onChange(ConfigChangeEvent changeEvent) { | |
} | ||
}; | ||
|
||
Set<String> interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null; | ||
Set<String> interestedKeyPrefixes = annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) : null; | ||
Set<String> interestedKeys = | ||
annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null; | ||
Set<String> interestedKeyPrefixes = | ||
annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) | ||
: null; | ||
|
||
for (String namespace : namespaces) { | ||
Config config = ConfigService.getConfig(namespace); | ||
final String resolvedNamespace = this.environment.resolveRequiredPlaceholders(namespace); | ||
Config config = ConfigService.getConfig(resolvedNamespace); | ||
|
||
if (interestedKeys == null && interestedKeyPrefixes == null) { | ||
config.addChangeListener(configChangeListener); | ||
|
@@ -76,4 +128,90 @@ public void onChange(ConfigChangeEvent changeEvent) { | |
} | ||
} | ||
} | ||
|
||
|
||
private void processApolloJsonValue(Object bean, String beanName, Field field) { | ||
ApolloJsonValue apolloJsonValue = AnnotationUtils.getAnnotation(field, ApolloJsonValue.class); | ||
if (apolloJsonValue == null) { | ||
return; | ||
} | ||
String placeholder = apolloJsonValue.value(); | ||
Object propertyValue = placeholderHelper | ||
.resolvePropertyValue(this.configurableBeanFactory, beanName, placeholder); | ||
|
||
// propertyValue will never be null, as @ApolloJsonValue will not allow that | ||
if (!(propertyValue instanceof String)) { | ||
return; | ||
} | ||
|
||
boolean accessible = field.isAccessible(); | ||
field.setAccessible(true); | ||
ReflectionUtils | ||
.setField(field, bean, parseJsonValue((String) propertyValue, field.getGenericType())); | ||
field.setAccessible(accessible); | ||
|
||
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) { | ||
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder); | ||
for (String key : keys) { | ||
SpringValue springValue = new SpringValue(key, placeholder, bean, beanName, field, true); | ||
springValueRegistry.register(this.configurableBeanFactory, key, springValue); | ||
logger.debug("Monitoring {}", springValue); | ||
} | ||
} | ||
} | ||
|
||
private void processApolloJsonValue(Object bean, String beanName, Method method) { | ||
ApolloJsonValue apolloJsonValue = AnnotationUtils.getAnnotation(method, ApolloJsonValue.class); | ||
if (apolloJsonValue == null) { | ||
return; | ||
} | ||
String placeHolder = apolloJsonValue.value(); | ||
|
||
Object propertyValue = placeholderHelper | ||
.resolvePropertyValue(this.configurableBeanFactory, beanName, placeHolder); | ||
|
||
// propertyValue will never be null, as @ApolloJsonValue will not allow that | ||
if (!(propertyValue instanceof String)) { | ||
return; | ||
} | ||
|
||
Type[] types = method.getGenericParameterTypes(); | ||
Preconditions.checkArgument(types.length == 1, | ||
"Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters", | ||
bean.getClass().getName(), method.getName(), method.getParameterTypes().length); | ||
|
||
boolean accessible = method.isAccessible(); | ||
method.setAccessible(true); | ||
ReflectionUtils.invokeMethod(method, bean, parseJsonValue((String) propertyValue, types[0])); | ||
method.setAccessible(accessible); | ||
|
||
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) { | ||
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeHolder); | ||
for (String key : keys) { | ||
SpringValue springValue = new SpringValue(key, apolloJsonValue.value(), bean, beanName, | ||
method, true); | ||
springValueRegistry.register(this.configurableBeanFactory, key, springValue); | ||
logger.debug("Monitoring {}", springValue); | ||
} | ||
} | ||
} | ||
|
||
private Object parseJsonValue(String json, Type targetType) { | ||
try { | ||
return GSON.fromJson(json, targetType); | ||
} catch (Throwable ex) { | ||
logger.error("Parsing json '{}' to type {} failed!", json, targetType, ex); | ||
throw ex; | ||
} | ||
} | ||
|
||
@Override | ||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { | ||
this.configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; | ||
} | ||
|
||
@Override | ||
public void setEnvironment(Environment environment) { | ||
this.environment = environment; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,15 @@ | |
* private Config config; | ||
* </pre> | ||
* | ||
* <p>Usage example with placeholder:</p> | ||
* <pre class="code"> | ||
* // The namespace could also be specified as a placeholder, e.g. ${redis.namespace:xxx}, | ||
* // which will use the value of the key "redis.namespace" or "xxx" if this key is not configured. | ||
* @ApolloConfig("${redis.namespace:xxx}") | ||
* private Config config; | ||
* </pre> | ||
* | ||
* | ||
* @author Jason Song([email protected]) | ||
*/ | ||
@Retention(RetentionPolicy.RUNTIME) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,18 +3,26 @@ | |
import com.ctrip.framework.apollo.spring.spi.ApolloConfigRegistrarHelper; | ||
import com.ctrip.framework.foundation.internals.ServiceBootstrap; | ||
import org.springframework.beans.factory.support.BeanDefinitionRegistry; | ||
import org.springframework.context.EnvironmentAware; | ||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; | ||
import org.springframework.core.env.Environment; | ||
import org.springframework.core.type.AnnotationMetadata; | ||
|
||
/** | ||
* @author Jason Song([email protected]) | ||
*/ | ||
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar { | ||
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware { | ||
|
||
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 setEnvironment(Environment environment) { | ||
this.helper.setEnvironment(environment); | ||
} | ||
|
||
} |
124 changes: 0 additions & 124 deletions
124
.../src/main/java/com/ctrip/framework/apollo/spring/annotation/ApolloJsonValueProcessor.java
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.