Initial commit

This commit is contained in:
Eric
2026-01-16 18:51:16 +08:00
commit 98c057de11
280 changed files with 16665 additions and 0 deletions

View File

@@ -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>

View File

@@ -0,0 +1,32 @@
package cn.lingniu.framework.plugin.apollo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.validation.constraints.NotBlank;
@Data
@ConfigurationProperties(prefix = ApolloConfig.PRE_FIX)
public class ApolloConfig {
public final static String PRE_FIX = "framework.lingniu.apollo";
/**
* 是否开始Apollo配置
*/
private Boolean enabled = true;
/**
* Meta地址
*/
@NotBlank
private String meta;
/**
* 配置文件列表 以,分割
*/
private String namespaces = "";
/**
* 无需配置 app.id 等于 spring.application.name
*/
private String appId;
}

View File

@@ -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);
}
}
}
}

View File

@@ -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 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;
import javax.annotation.Resource;
@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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,52 @@
package cn.lingniu.framework.plugin.apollo.extend;
import com.ctrip.framework.apollo.core.spi.Ordered;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValueProcessor;
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.SpringValueDefinitionProcessor;
import com.ctrip.framework.apollo.spring.util.BeanRegistrationUtil;
import com.google.common.collect.Lists;
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;
import java.util.HashMap;
import java.util.Map;
public class FrameworkApolloConfigRegistrarHelper implements com.ctrip.framework.apollo.spring.spi.ApolloConfigRegistrarHelper, Ordered {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(EnableApolloConfig.class.getName()));
String[] namespaces = System.getProperty("apollo.bootstrap.namespaces", "application").split(",");
//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);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
PropertySourcesProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
ApolloAnnotationProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(),
SpringValueProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(),
SpringValueDefinitionProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
ApolloJsonValueProcessor.class);
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 10;
}
}

View File

@@ -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"));
}
}

View File

@@ -0,0 +1,114 @@
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.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 static boolean isload = false;
private String applicationName;
public final static String PROJECT = "Apollo";
private final static String AppId = "app.id";
public final static String ApolloMeta = "apollo.meta";
private final static String ApolloBootstrapEnabled = "apollo.bootstrap.enabled";
private final static String ApolloBootstrapNamespaces = "apollo.bootstrap.namespaces";
private final static String ApolloBootstrapEagerLoadEnabled = "apollo.bootstrap.eagerLoad.enabled";
private final static String UserDir = "user.dir";
private final static String ApolloCacheDir = "apollo.cacheDir";
public final static String Env = "env";
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))) {
this.replaceCatInit(environment);
return;
}
if (ObjectEmptyUtils.isEmpty(environment.getProperty(FrameworkEnabled)) || environment.getProperty(FrameworkEnabled).equalsIgnoreCase("false")) {
setDefaultProperty(ApolloBootstrapEnabled, "false");
setDefaultProperty(ApolloBootstrapEagerLoadEnabled, "false");
return;
}
//默认设置app.id
PropertyUtils.setDefaultInitProperty(AppId, appName);
setDefaultProperty(ApolloMeta, environment.getProperty(FrameworkMeta));
setDefaultProperty(ApolloBootstrapEnabled, "true");
setDefaultProperty(ApolloBootstrapNamespaces, environment.getProperty(NameSpaces, "application"));
setDefaultProperty(ApolloBootstrapEagerLoadEnabled, "true");
setDefaultProperty("spring.boot.enableautoconfiguration", "true");
setDefaultProperty(Env, profile.toUpperCase());
setDefaultProperty(ApolloCacheDir, System.getProperty(UserDir) + File.separator + "apolloConfig" + File.separator);
this.replaceCatInit(environment);
}
private void replaceCatInit(ConfigurableEnvironment environment) {
try {
ClassPool classPool = ClassPoolUtils.getInstance();
CtClass ctClass = classPool.get("com.ctrip.framework.apollo.tracer.internals.DefaultMessageProducerManager");
if (!isload) {
isload = true;
CtConstructor[] constructors = ctClass.getConstructors();
if (constructors != null && constructors.length > 0) {
CtConstructor constructor = constructors[0];
constructor.setBody(newMethodCode());
}
if (ctClass.isFrozen()) {
ctClass.defrost();
}
ctClass.toClass();
log.info("{} {} {}", ApolloInit.class, PROJECT, "重写 apollo init ok");
}
} catch (Exception exp) {
log.error("{} {} {} {}", ApolloInit.class, PROJECT, "重写 apollo init 异常", exp);
}
}
private String newMethodCode() {
String code = "{" + " producer = new com.ctrip.framework.apollo.tracer.internals.NullMessageProducerManager().getProducer();" + "}";
return code;
}
void setDefaultProperty(String key, String defaultPropertyValue) {
PropertyUtils.setDefaultInitProperty(key, defaultPropertyValue);
}
}

View File

@@ -0,0 +1 @@
cn.lingniu.framework.plugin.apollo.extend.FrameworkApolloConfigRegistrarHelper

View File

@@ -0,0 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.lingniu.framework.plugin.apollo.init.ApolloAutoConfiguration
org.springframework.context.ApplicationContextInitializer=\
cn.lingniu.framework.plugin.apollo.init.ApolloInit

View File

@@ -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 可配置多个配置文件