jdk17 commit
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../lingniu-framework-dependencies/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>lingniu-framework-plugin-apollo</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.lingniu.framework.plugin.apollo.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = ApolloConfig.PRE_FIX)
|
||||
public class ApolloConfig {
|
||||
|
||||
public final static String PRE_FIX = "framework.lingniu.apollo";
|
||||
|
||||
/**
|
||||
* 是否开始Apollo配置
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
/**
|
||||
* Meta地址
|
||||
*/
|
||||
private String meta;
|
||||
/**
|
||||
* 配置文件列表 以,分割
|
||||
*/
|
||||
private String namespaces = "";
|
||||
/**
|
||||
* 无需配置 app.id 等于 spring.application.name
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import com.ctrip.framework.apollo.Config;
|
||||
import com.ctrip.framework.apollo.ConfigChangeListener;
|
||||
import com.ctrip.framework.apollo.ConfigService;
|
||||
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloProcessor;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Apollo Annotation Processor for Spring Application
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public class ApolloAnnotationProcessor extends ApolloProcessor {
|
||||
|
||||
@Override
|
||||
protected void processField(Object bean, String beanName, Field field) {
|
||||
ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class);
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()),
|
||||
"Invalid type: %s for field: %s, should be Config", field.getType(), field);
|
||||
|
||||
String namespace = System.getProperty("apollo.bootstrap.namespaces", annotation.value());
|
||||
Config config = ConfigService.getConfig(namespace);
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, bean, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processMethod(final Object bean, String beanName, final Method method) {
|
||||
ApolloConfigChangeListener annotation = AnnotationUtils
|
||||
.findAnnotation(method, ApolloConfigChangeListener.class);
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Preconditions.checkArgument(parameterTypes.length == 1,
|
||||
"Invalid number of parameters: %s for method: %s, should be 1", parameterTypes.length,
|
||||
method);
|
||||
Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]),
|
||||
"Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", parameterTypes[0],
|
||||
method);
|
||||
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
|
||||
String namespaceProperties = System.getProperty("apollo.bootstrap.namespaces", String.join(",", annotation.value()));
|
||||
String[] namespaces = namespaceProperties.split(",");
|
||||
String[] annotatedInterestedKeys = annotation.interestedKeys();
|
||||
String[] annotatedInterestedKeyPrefixes = annotation.interestedKeyPrefixes();
|
||||
ConfigChangeListener configChangeListener = changeEvent -> ReflectionUtils.invokeMethod(method, bean, changeEvent);
|
||||
|
||||
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);
|
||||
|
||||
if (interestedKeys == null && interestedKeyPrefixes == null) {
|
||||
config.addChangeListener(configChangeListener);
|
||||
} else {
|
||||
config.addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import cn.lingniu.framework.plugin.util.validation.ObjectEmptyUtils;
|
||||
import com.ctrip.framework.apollo.model.ConfigChange;
|
||||
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.cloud.context.scope.refresh.RefreshScope;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ApolloConfigChangeLogListener implements ApplicationContextAware {
|
||||
|
||||
@Resource
|
||||
RefreshScope refreshScope;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@ApolloConfigChangeListener
|
||||
public void onChange(ConfigChangeEvent changeEvent) {
|
||||
if (log.isInfoEnabled()) {
|
||||
for (String changedKey : changeEvent.changedKeys()) {
|
||||
ConfigChange changeInfo = changeEvent.getChange(changedKey);
|
||||
if (ObjectEmptyUtils.isEmpty(changeInfo)) {
|
||||
continue;
|
||||
}
|
||||
log.info("【apollo 配置变更】 - namespace: {}, property: {}, oldValue: {}, newValue: {}, changeType: {}",
|
||||
changeInfo.getNamespace(), changeInfo.getPropertyName(),
|
||||
changeInfo.getOldValue(), changeInfo.getNewValue(), changeInfo.getChangeType());
|
||||
}
|
||||
}
|
||||
applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
|
||||
refreshProperties(changeEvent);
|
||||
}
|
||||
|
||||
public void refreshProperties(ConfigChangeEvent changeEvent) {
|
||||
try {
|
||||
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
|
||||
if (ObjectEmptyUtils.isNotEmpty(refreshScope)) {
|
||||
refreshScope.refreshAll();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to refresh properties after Apollo config change", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.LoaderClassPath;
|
||||
|
||||
|
||||
public class ClassPoolUtils {
|
||||
|
||||
private static volatile ClassPool instance;
|
||||
|
||||
private ClassPoolUtils() {
|
||||
}
|
||||
|
||||
public static ClassPool getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (ClassPoolUtils.class) {
|
||||
if (instance == null) {
|
||||
instance = ClassPool.getDefault();
|
||||
instance.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import com.ctrip.framework.apollo.core.spi.Ordered;
|
||||
import com.ctrip.framework.apollo.spring.annotation.SpringValueProcessor;
|
||||
import com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener;
|
||||
import com.ctrip.framework.apollo.spring.property.SpringValueDefinitionProcessor;
|
||||
import com.ctrip.framework.apollo.spring.spi.ConfigPropertySourcesProcessorHelper;
|
||||
import com.ctrip.framework.apollo.spring.util.BeanRegistrationUtil;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class FramewokConfigPropertySourcesProcessorHelper implements ConfigPropertySourcesProcessorHelper {
|
||||
|
||||
@Override
|
||||
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);
|
||||
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class,
|
||||
propertySourcesPlaceholderPropertyValues);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, AutoUpdateConfigChangeListener.class);//
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, FrameworkApolloAnnotationProcessor.class); //扩展 Apollo 注解处理器
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class);
|
||||
|
||||
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...
|
||||
*/
|
||||
private void processSpringValueDefinition(BeanDefinitionRegistry registry) {
|
||||
SpringValueDefinitionProcessor springValueDefinitionProcessor = new SpringValueDefinitionProcessor();
|
||||
springValueDefinitionProcessor.postProcessBeanDefinitionRegistry(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE - 10 ; // 优先级放高
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
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.core.utils.StringUtils;
|
||||
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloAnnotationProcessor;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloProcessor;
|
||||
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.common.base.Splitter;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Apollo Annotation Processor for Spring Application
|
||||
*/
|
||||
public class FrameworkApolloAnnotationProcessor extends ApolloProcessor implements BeanFactoryAware,
|
||||
EnvironmentAware {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ApolloAnnotationProcessor.class);
|
||||
|
||||
private static final String NAMESPACE_DELIMITER = ",";
|
||||
|
||||
private static final Splitter NAMESPACE_SPLITTER = Splitter.on(NAMESPACE_DELIMITER)
|
||||
.omitEmptyStrings().trimResults();
|
||||
private static final Map<String, Gson> DATEPATTERN_GSON_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConfigUtil configUtil; // 配置工具类
|
||||
private final PlaceholderHelper placeholderHelper;
|
||||
private final SpringValueRegistry springValueRegistry;
|
||||
|
||||
/**
|
||||
* resolve the expression.
|
||||
*/
|
||||
private ConfigurableBeanFactory configurableBeanFactory;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
public FrameworkApolloAnnotationProcessor() {
|
||||
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);
|
||||
}
|
||||
// 处理Bean方法上的Apollo注解
|
||||
@Override
|
||||
protected void processMethod(final Object bean, String beanName, final Method method) {
|
||||
this.processApolloConfigChangeListener(bean, method);
|
||||
this.processApolloJsonValue(bean, beanName, method);
|
||||
}
|
||||
// field-具体注解处理方法--处理@ApolloConfig字段注解
|
||||
private void processApolloConfig(Object bean, Field field) {
|
||||
ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class);
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()),
|
||||
"Invalid type: %s for field: %s, should be Config", field.getType(), field);
|
||||
final String appId = StringUtils.defaultIfBlank(annotation.appId(), configUtil.getAppId());
|
||||
final String namespace = annotation.value();
|
||||
final String resolvedAppId = this.environment.resolveRequiredPlaceholders(appId);
|
||||
final String resolvedNamespace = this.environment.resolveRequiredPlaceholders(namespace);
|
||||
Config config = ConfigService.getConfig(resolvedAppId, resolvedNamespace);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, bean, config);
|
||||
}
|
||||
private void processApolloConfigChangeListener(final Object bean, final Method method) {
|
||||
ApolloConfigChangeListener annotation = AnnotationUtils
|
||||
.findAnnotation(method, ApolloConfigChangeListener.class);
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Preconditions.checkArgument(parameterTypes.length == 1,
|
||||
"Invalid number of parameters: %s for method: %s, should be 1", parameterTypes.length,
|
||||
method);
|
||||
Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]),
|
||||
"Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", parameterTypes[0],
|
||||
method);
|
||||
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
String appId = StringUtils.defaultIfBlank(annotation.appId(), configUtil.getAppId());
|
||||
String namespaceProperties =System.getProperty("apollo.bootstrap.namespaces",String.join( "," ,annotation.value())); //todo 默认处理所有-bootstrap.namespaces
|
||||
String[] namespaces = namespaceProperties.split(",");
|
||||
String[] annotatedInterestedKeys = annotation.interestedKeys();
|
||||
String[] annotatedInterestedKeyPrefixes = annotation.interestedKeyPrefixes();
|
||||
ConfigChangeListener configChangeListener = changeEvent -> ReflectionUtils.invokeMethod(method, bean, changeEvent);
|
||||
|
||||
Set<String> interestedKeys =
|
||||
annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null;
|
||||
Set<String> interestedKeyPrefixes =
|
||||
annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes)
|
||||
: null;
|
||||
|
||||
Set<String> resolvedNamespaces = processResolveNamespaceValue(namespaces);
|
||||
|
||||
for (String namespace : resolvedNamespaces) {
|
||||
Config config = ConfigService.getConfig(appId, namespace);
|
||||
|
||||
if (interestedKeys == null && interestedKeyPrefixes == null) {
|
||||
config.addChangeListener(configChangeListener);
|
||||
} else {
|
||||
config.addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate and resolve namespaces from env/properties.
|
||||
* Split delimited namespaces
|
||||
* @param namespaces
|
||||
* @return resolved namespaces
|
||||
*/
|
||||
private Set<String> processResolveNamespaceValue(String[] namespaces) {
|
||||
|
||||
Set<String> resolvedNamespaces = new HashSet<>();
|
||||
|
||||
for (String namespace : namespaces) {
|
||||
final String resolvedNamespace = this.environment.resolveRequiredPlaceholders(namespace);
|
||||
|
||||
if (resolvedNamespace.contains(NAMESPACE_DELIMITER)) {
|
||||
resolvedNamespaces.addAll(NAMESPACE_SPLITTER.splitToList(resolvedNamespace));
|
||||
} else {
|
||||
resolvedNamespaces.add(resolvedNamespace);
|
||||
}
|
||||
}
|
||||
|
||||
return resolvedNamespaces;
|
||||
}
|
||||
|
||||
private void processApolloJsonValue(Object bean, String beanName, Field field) {
|
||||
ApolloJsonValue apolloJsonValue = AnnotationUtils.getAnnotation(field, ApolloJsonValue.class);
|
||||
if (apolloJsonValue == null) {
|
||||
return; // 处理方法上的@ApolloJsonValue注解
|
||||
}
|
||||
|
||||
String placeholder = apolloJsonValue.value();
|
||||
String datePattern = apolloJsonValue.datePattern();
|
||||
Object propertyValue = this.resolvePropertyValue(beanName, placeholder);
|
||||
if (propertyValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean accessible = field.isAccessible();
|
||||
field.setAccessible(true);
|
||||
ReflectionUtils
|
||||
.setField(field, bean, parseJsonValue((String) propertyValue, field.getGenericType(), datePattern));
|
||||
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();
|
||||
String datePattern = apolloJsonValue.datePattern();
|
||||
Object propertyValue = this.resolvePropertyValue(beanName, placeHolder);
|
||||
if (propertyValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Type[] types = method.getGenericParameterTypes();
|
||||
Preconditions.checkArgument(types.length == 1,
|
||||
"Ignore @ApolloJsonValue setter {}.{}, expecting 1 parameter, actual {} parameters",
|
||||
bean.getClass().getName(), method.getName(), method.getParameterTypes().length);
|
||||
|
||||
boolean accessible = method.isAccessible();
|
||||
method.setAccessible(true); // 解析占位符获取JSON值
|
||||
ReflectionUtils.invokeMethod(method, bean, parseJsonValue((String) propertyValue, types[0], datePattern));
|
||||
method.setAccessible(accessible);
|
||||
|
||||
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
|
||||
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeHolder);
|
||||
for (String key : keys) {
|
||||
SpringValue springValue = new SpringValue(key, placeHolder, bean, beanName, method, true);
|
||||
springValueRegistry.register(this.configurableBeanFactory, key, springValue);
|
||||
logger.debug("Monitoring {}", springValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object resolvePropertyValue(String beanName, String placeHolder) {
|
||||
Object propertyValue = placeholderHelper
|
||||
.resolvePropertyValue(this.configurableBeanFactory, beanName, placeHolder);
|
||||
|
||||
// propertyValue will never be null, as @ApolloJsonValue will not allow that
|
||||
if (!(propertyValue instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
private Object parseJsonValue(String json, Type targetType, String datePattern) {
|
||||
try {
|
||||
return DATEPATTERN_GSON_MAP.computeIfAbsent(datePattern, this::buildGson).fromJson(json, targetType);
|
||||
} catch (Throwable ex) {
|
||||
logger.error("Parsing json '{}' to type {} failed!", json, targetType, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private Gson buildGson(String datePattern) {
|
||||
if (StringUtils.isBlank(datePattern)) {
|
||||
return new Gson();
|
||||
}
|
||||
return new GsonBuilder().setDateFormat(datePattern).create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import com.ctrip.framework.apollo.build.ApolloInjector;
|
||||
import com.ctrip.framework.apollo.core.spi.Ordered;
|
||||
import com.ctrip.framework.apollo.core.utils.StringUtils;
|
||||
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
|
||||
import com.ctrip.framework.apollo.spring.annotation.SpringValueProcessor;
|
||||
import com.ctrip.framework.apollo.spring.config.PropertySourcesProcessor;
|
||||
import com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener;
|
||||
import com.ctrip.framework.apollo.spring.property.SpringValueDefinitionProcessor;
|
||||
import com.ctrip.framework.apollo.spring.spi.DefaultApolloConfigRegistrarHelper;
|
||||
import com.ctrip.framework.apollo.spring.util.BeanRegistrationUtil;
|
||||
import com.ctrip.framework.apollo.util.ConfigUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class FrameworkApolloConfigRegistrarHelper implements com.ctrip.framework.apollo.spring.spi.ApolloConfigRegistrarHelper, Ordered {
|
||||
private static final Logger logger = LoggerFactory.getLogger(
|
||||
DefaultApolloConfigRegistrarHelper.class);
|
||||
|
||||
private final ConfigUtil configUtil = ApolloInjector.getInstance(ConfigUtil.class);
|
||||
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
AnnotationAttributes attributes = AnnotationAttributes
|
||||
.fromMap(importingClassMetadata.getAnnotationAttributes(EnableApolloConfig.class.getName()));
|
||||
final String[] namespaces = System.getProperty("apollo.bootstrap.namespaces","application").split(","); //todo 默认处理所有-bootstrap.namespaces
|
||||
final int order = attributes.getNumber("order");
|
||||
|
||||
// put main appId
|
||||
PropertySourcesProcessor.addNamespaces(configUtil.getAppId(), Lists.newArrayList(this.resolveNamespaces(namespaces)), order);
|
||||
|
||||
// put multiple appId into
|
||||
AnnotationAttributes[] multipleConfigs = attributes.getAnnotationArray("multipleConfigs");
|
||||
if (multipleConfigs != null) {
|
||||
for (AnnotationAttributes multipleConfig : multipleConfigs) {
|
||||
String appId = multipleConfig.getString("appId");
|
||||
String[] multipleNamespaces = this.resolveNamespaces(multipleConfig.getStringArray("namespaces"));
|
||||
String secret = resolveSecret(multipleConfig.getString("secret"));
|
||||
int multipleOrder = multipleConfig.getNumber("order");
|
||||
|
||||
// put multiple secret into system property
|
||||
if (!StringUtils.isBlank(secret)) {
|
||||
System.setProperty("apollo.accesskey." + appId + ".secret", secret);
|
||||
}
|
||||
PropertySourcesProcessor.addNamespaces(appId, Lists.newArrayList(multipleNamespaces), multipleOrder);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
|
||||
// to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
|
||||
propertySourcesPlaceholderPropertyValues.put("order", 0);
|
||||
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class,
|
||||
propertySourcesPlaceholderPropertyValues); // 属性占位符配置器
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, AutoUpdateConfigChangeListener.class);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, FrameworkApolloAnnotationProcessor.class); //todo 扩展的Apollo 注解处理器
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class);
|
||||
}
|
||||
|
||||
private String[] resolveNamespaces(String[] namespaces) {
|
||||
// no support for Spring version prior to 3.2.x, see https://github.com/apolloconfig/apollo/issues/4178
|
||||
if (this.environment == null) {
|
||||
logNamespacePlaceholderNotSupportedMessage(namespaces);
|
||||
return namespaces;
|
||||
}
|
||||
String[] resolvedNamespaces = new String[namespaces.length];
|
||||
for (int i = 0; i < namespaces.length; i++) {
|
||||
// throw IllegalArgumentException if given text is null or if any placeholders are unresolvable
|
||||
resolvedNamespaces[i] = this.environment.resolveRequiredPlaceholders(namespaces[i]);
|
||||
}
|
||||
return resolvedNamespaces;
|
||||
}
|
||||
|
||||
private String resolveSecret(String secret){
|
||||
if (this.environment == null) {
|
||||
if (secret != null && secret.contains("${")) {
|
||||
logger.warn("secret placeholder {} is not supported for Spring version prior to 3.2.x", secret);
|
||||
}
|
||||
return secret;
|
||||
}
|
||||
return this.environment.resolveRequiredPlaceholders(secret);
|
||||
}
|
||||
|
||||
private void logNamespacePlaceholderNotSupportedMessage(String[] namespaces) {
|
||||
for (String namespace : namespaces) {
|
||||
if (namespace.contains("${")) {
|
||||
logger.warn("Namespace placeholder {} is not supported for Spring version prior to 3.2.x,"
|
||||
+ " see https://github.com/apolloconfig/apollo/issues/4178 for more details.",
|
||||
namespace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE - 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.lingniu.framework.plugin.apollo.init;
|
||||
|
||||
import cn.lingniu.framework.plugin.apollo.extend.ApolloConfigChangeLogListener;
|
||||
import cn.lingniu.framework.plugin.apollo.config.ApolloConfig;
|
||||
import cn.lingniu.framework.plugin.util.config.PropertyUtils;
|
||||
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableApolloConfig
|
||||
@ConditionalOnProperty(prefix = ApolloConfig.PRE_FIX, name = "enabled", havingValue = "true")
|
||||
@Import({ApolloConfigChangeLogListener.class})
|
||||
public class ApolloAutoConfiguration implements InitializingBean {
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
log.info("Apollo configuration enabled(启动), meta URL: {}", PropertyUtils.getProperty("apollo.meta"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package cn.lingniu.framework.plugin.apollo.init;
|
||||
|
||||
|
||||
import cn.lingniu.framework.plugin.apollo.config.ApolloConfig;
|
||||
import cn.lingniu.framework.plugin.apollo.extend.ClassPoolUtils;
|
||||
import cn.lingniu.framework.plugin.core.config.CommonConstant;
|
||||
import cn.lingniu.framework.plugin.core.context.ApplicationNameContext;
|
||||
import cn.lingniu.framework.plugin.util.validation.ObjectEmptyUtils;
|
||||
import cn.lingniu.framework.plugin.util.config.PropertyUtils;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* apollo 初始化
|
||||
*/
|
||||
@Slf4j
|
||||
@Order(Integer.MIN_VALUE + 100)
|
||||
public class ApolloInit implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
|
||||
private String applicationName;
|
||||
|
||||
private final static String AppId = "app.id";
|
||||
private final static String ApolloMeta = "apollo.meta";
|
||||
private final static String ApolloBootstrapEnabled = "apollo.bootstrap.enabled";
|
||||
private final static String ApolloBootstrapEagerLoadEnabled = "apollo.bootstrap.eagerLoad.enabled";
|
||||
private final static String UserDir = "user.dir";
|
||||
|
||||
public final static String NameSpaces = "framework.lingniu.apollo.namespaces";
|
||||
public final static String FrameworkMeta = "framework.lingniu.apollo.meta";
|
||||
public final static String FrameworkEnabled = "framework.lingniu.apollo.enabled";
|
||||
|
||||
|
||||
private final static String APOLLO_NAME = ApolloConfig.PRE_FIX + ".name";
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
ConfigurableEnvironment environment = applicationContext.getEnvironment();
|
||||
applicationName = environment.getProperty(APOLLO_NAME, environment.getProperty(CommonConstant.SPRING_APP_NAME_KEY));
|
||||
String profile = environment.getProperty(CommonConstant.ACTIVE_PROFILES_PROPERTY);
|
||||
this.initApolloConfig(environment, applicationName, profile);
|
||||
}
|
||||
|
||||
|
||||
void initApolloConfig(ConfigurableEnvironment environment, String appName, String profile) {
|
||||
//优先原始配置
|
||||
if (!ObjectEmptyUtils.isEmpty(environment.getProperty(ApolloBootstrapEnabled))
|
||||
&& !ObjectEmptyUtils.isEmpty(environment.getProperty(ApolloMeta))
|
||||
&& !ObjectEmptyUtils.isEmpty(environment.getProperty(AppId))) {
|
||||
return;
|
||||
}
|
||||
if (ObjectEmptyUtils.isEmpty(environment.getProperty(FrameworkEnabled)) || environment.getProperty(FrameworkEnabled).equalsIgnoreCase("false")) {
|
||||
setDefaultProperty(ApolloBootstrapEnabled, "false");
|
||||
setDefaultProperty(ApolloBootstrapEagerLoadEnabled, "false");
|
||||
return;
|
||||
}
|
||||
PropertyUtils.setDefaultInitProperty("app.id", "test-ln");
|
||||
// PropertyUtils.setDefaultInitProperty("app.id", appName);
|
||||
setDefaultProperty("apollo.meta", environment.getProperty(FrameworkMeta));
|
||||
setDefaultProperty("apollo.bootstrap.enabled", "true");
|
||||
setDefaultProperty("apollo.bootstrap.namespaces", environment.getProperty(NameSpaces, "application"));
|
||||
setDefaultProperty("apollo.bootstrap.eagerLoad.enabled", "true");
|
||||
setDefaultProperty("spring.boot.enableautoconfiguration", "true");
|
||||
setDefaultProperty("env",profile.toUpperCase());
|
||||
setDefaultProperty("apollo.cache-dir", System.getProperty(UserDir) + File.separator + "apolloConfig" + File.separator);
|
||||
|
||||
}
|
||||
|
||||
void setDefaultProperty(String key, String defaultPropertyValue) {
|
||||
PropertyUtils.setDefaultInitProperty(key, defaultPropertyValue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cn.lingniu.framework.plugin.apollo.extend.FrameworkApolloConfigRegistrarHelper
|
||||
@@ -0,0 +1 @@
|
||||
cn.lingniu.framework.plugin.apollo.extend.FramewokConfigPropertySourcesProcessorHelper
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.context.ApplicationContextInitializer=\
|
||||
cn.lingniu.framework.plugin.apollo.init.ApolloInit
|
||||
@@ -0,0 +1 @@
|
||||
cn.lingniu.framework.plugin.apollo.init.ApolloAutoConfiguration
|
||||
@@ -0,0 +1,37 @@
|
||||
# 【重要】apllo服务搭建、和详细demo使用教程---参考官网
|
||||
|
||||
## 概述 (Overview)
|
||||
|
||||
1. 定位:基于 Apollo 封装的分布式配置管理中心组件
|
||||
2. 核心能力
|
||||
* 集中化配置管理:统一管理不同环境、不同集群的配置
|
||||
* 实时推送更新:配置变更后实时推送到应用端,无需重启服务
|
||||
* 多环境支持:支持开发、测试、生产等多套环境配置隔离
|
||||
3. 适用场景
|
||||
* 微服务架构下的配置管理
|
||||
* 多环境、多集群的应用配置管理
|
||||
* 需要动态调整配置参数的业务场
|
||||
* 对配置变更实时性要求较高的系统
|
||||
|
||||
## 如何配置--参考:ApolloConfig类
|
||||
|
||||
```yaml
|
||||
framework:
|
||||
lingniu:
|
||||
apollo:
|
||||
#namespaces必须配置,配置文件列表,以逗号分割
|
||||
namespaces: application,applicationTest
|
||||
# 是否开启 Apollo 配置,默认true
|
||||
enabled: true
|
||||
# appId 等于 spring.application.name,无需配置
|
||||
appId: lingniu-framework-demo
|
||||
# meta 地址,框架自动获取,无需配置
|
||||
meta: http://xxx:8180
|
||||
```
|
||||
|
||||
## 核心参数描述
|
||||
|
||||
- app.id:此参数未配置,默认采用:spring.application.name
|
||||
- framework.lingniu.apollo.meta: 为apollo的eurka注册地址
|
||||
- framework.lingniu.apollo.enabled:是否启用
|
||||
- framework.lingniu.apollo.namespaces 可配置多个配置文件
|
||||
Reference in New Issue
Block a user