实现配置中心的基础
parent
d2fa839d3c
commit
ec9ed896f9
@ -0,0 +1,28 @@
|
||||
package cn.iocoder.dashboard.framework.apollox;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 配置接口
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public interface Config {
|
||||
|
||||
/**
|
||||
* Return the property value with the given key, or {@code defaultValue} if the key doesn't exist.
|
||||
*
|
||||
* @param key the property name
|
||||
* @param defaultValue the default value when key is not found or any error occurred
|
||||
* @return the property value
|
||||
*/
|
||||
String getProperty(String key, String defaultValue);
|
||||
|
||||
/**
|
||||
* Return a set of the property names
|
||||
*
|
||||
* @return the property names
|
||||
*/
|
||||
Set<String> getPropertyNames();
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package cn.iocoder.dashboard.framework.apollox;
|
||||
|
||||
import cn.iocoder.dashboard.framework.apollox.model.ConfigChangeEvent;
|
||||
|
||||
/**
|
||||
* {@link Config} 变化监听器
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public interface ConfigChangeListener {
|
||||
|
||||
/**
|
||||
* Invoked when there is any config change for the namespace.
|
||||
*
|
||||
* @param changeEvent the event for this change
|
||||
*/
|
||||
void onChange(ConfigChangeEvent changeEvent);
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package cn.iocoder.dashboard.framework.apollox;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class DBConfig implements Config {
|
||||
|
||||
@Override
|
||||
public String getProperty(String key, String defaultValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPropertyNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.enums;
|
||||
|
||||
/**
|
||||
* 属性变化类型枚举
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public enum PropertyChangeType {
|
||||
|
||||
ADDED, // 添加
|
||||
MODIFIED, // 修改
|
||||
DELETED // 删除
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.model;
|
||||
|
||||
|
||||
import cn.iocoder.dashboard.framework.apollox.enums.PropertyChangeType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Holds the information for a config change.
|
||||
* 配置每个属性变化的信息
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ConfigChange {
|
||||
|
||||
/**
|
||||
* 属性名
|
||||
*/
|
||||
private final String propertyName;
|
||||
/**
|
||||
* 老值
|
||||
*/
|
||||
private String oldValue;
|
||||
/**
|
||||
* 新值
|
||||
*/
|
||||
private String newValue;
|
||||
/**
|
||||
* 变化类型
|
||||
*/
|
||||
private PropertyChangeType changeType;
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.boot;
|
||||
|
||||
|
||||
import cn.hutool.core.lang.Singleton;
|
||||
import cn.iocoder.dashboard.framework.apollox.Config;
|
||||
import cn.iocoder.dashboard.framework.apollox.DBConfig;
|
||||
import cn.iocoder.dashboard.framework.apollox.spring.config.ConfigPropertySource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static cn.iocoder.dashboard.framework.apollox.spring.config.PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME;
|
||||
|
||||
@Slf4j
|
||||
public class ApolloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext context) {
|
||||
ConfigurableEnvironment environment = context.getEnvironment();
|
||||
// 忽略,若已经有 APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME 的 PropertySource
|
||||
if (environment.getPropertySources().contains(APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
|
||||
// already initialized
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建自定义的 APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME 的 PropertySource
|
||||
Config config = Singleton.get(DBConfig.class);
|
||||
ConfigPropertySource configPropertySource = new ConfigPropertySource(APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME, config);
|
||||
// 添加到 `environment` 中,且优先级最高
|
||||
environment.getPropertySources().addFirst(configPropertySource);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.boot;
|
||||
|
||||
import cn.iocoder.dashboard.framework.apollox.spring.config.ConfigPropertySourcesProcessor;
|
||||
import cn.iocoder.dashboard.framework.apollox.spring.property.PropertySourcesProcessor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(PropertySourcesProcessor.class) // 缺失 PropertySourcesProcessor 时
|
||||
public class ApolloAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ConfigPropertySourcesProcessor configPropertySourcesProcessor() {
|
||||
return new ConfigPropertySourcesProcessor(); // 注入 ConfigPropertySourcesProcessor bean 对象
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.config;
|
||||
|
||||
import cn.iocoder.dashboard.framework.apollox.Config;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property source wrapper for Config
|
||||
*
|
||||
* 基于 {@link Config} 的 PropertySource 实现类
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public class ConfigPropertySource extends EnumerablePropertySource<Config> {
|
||||
|
||||
private static final String[] EMPTY_ARRAY = new String[0];
|
||||
|
||||
public 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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.config;
|
||||
|
||||
import cn.iocoder.dashboard.framework.apollox.spring.annotation.SpringValueProcessor;
|
||||
import cn.iocoder.dashboard.framework.apollox.spring.property.PropertySourcesProcessor;
|
||||
import cn.iocoder.dashboard.framework.apollox.spring.property.SpringValueDefinitionProcessor;
|
||||
import cn.iocoder.dashboard.framework.apollox.spring.util.BeanRegistrationUtil;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
|
||||
/**
|
||||
* Apollo Property Sources processor for Spring XML Based Application
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public class ConfigPropertySourcesProcessor extends PropertySourcesProcessor implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
// 注册 PropertySourcesPlaceholderConfigurer 到 BeanDefinitionRegistry 中,替换 PlaceHolder 为对应的属性值,参考文章 https://leokongwq.github.io/2016/12/28/spring-PropertyPlaceholderConfigurer.html
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(), PropertySourcesPlaceholderConfigurer.class);
|
||||
// 注册 SpringValueProcessor 到 BeanDefinitionRegistry 中,用于 PlaceHolder 自动更新机制
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.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...
|
||||
*/
|
||||
private void processSpringValueDefinition(BeanDefinitionRegistry registry) {
|
||||
// 创建 SpringValueDefinitionProcessor 对象
|
||||
SpringValueDefinitionProcessor springValueDefinitionProcessor = new SpringValueDefinitionProcessor();
|
||||
// 处理 XML 配置的 Spring PlaceHolder
|
||||
springValueDefinitionProcessor.postProcessBeanDefinitionRegistry(registry);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.config;
|
||||
|
||||
public interface PropertySourcesConstants {
|
||||
|
||||
String APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME = "ApolloBootstrapPropertySources";
|
||||
|
||||
}
|
||||
@ -0,0 +1,160 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.property;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Placeholder 工具类
|
||||
*
|
||||
* Placeholder helper functions.
|
||||
*/
|
||||
public class PlaceholderHelper {
|
||||
|
||||
private static final String PLACEHOLDER_PREFIX = "${";
|
||||
private static final String PLACEHOLDER_SUFFIX = "}";
|
||||
private static final String VALUE_SEPARATOR = ":";
|
||||
private static final String SIMPLE_PLACEHOLDER_PREFIX = "{";
|
||||
private static final String EXPRESSION_PREFIX = "#{";
|
||||
private static final String EXPRESSION_SUFFIX = "}";
|
||||
|
||||
/**
|
||||
* Resolve placeholder property values, e.g.
|
||||
*
|
||||
* "${somePropertyValue}" -> "the actual property value"
|
||||
*/
|
||||
public Object resolvePropertyValue(ConfigurableBeanFactory beanFactory, String beanName, String placeholder) {
|
||||
// resolve string value
|
||||
String strVal = beanFactory.resolveEmbeddedValue(placeholder);
|
||||
// 获得 BeanDefinition 对象
|
||||
BeanDefinition bd = (beanFactory.containsBean(beanName) ? beanFactory.getMergedBeanDefinition(beanName) : null);
|
||||
// resolve expressions like "#{systemProperties.myProp}"
|
||||
return evaluateBeanDefinitionString(beanFactory, strVal, bd);
|
||||
}
|
||||
|
||||
private Object evaluateBeanDefinitionString(ConfigurableBeanFactory beanFactory, String value, BeanDefinition beanDefinition) {
|
||||
if (beanFactory.getBeanExpressionResolver() == null) {
|
||||
return value;
|
||||
}
|
||||
Scope scope = (beanDefinition != null ? beanFactory.getRegisteredScope(beanDefinition.getScope()) : null);
|
||||
return beanFactory.getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(beanFactory, scope));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract keys from placeholder, e.g.
|
||||
* <ul>
|
||||
* <li>${some.key} => "some.key"</li>
|
||||
* <li>${some.key:${some.other.key:100}} => "some.key", "some.other.key"</li>
|
||||
* <li>${${some.key}} => "some.key"</li>
|
||||
* <li>${${some.key:other.key}} => "some.key"</li>
|
||||
* <li>${${some.key}:${another.key}} => "some.key", "another.key"</li>
|
||||
* <li>#{new java.text.SimpleDateFormat('${some.key}').parse('${another.key}')} => "some.key", "another.key"</li>
|
||||
* </ul>
|
||||
*/
|
||||
public Set<String> extractPlaceholderKeys(String propertyString) {
|
||||
Set<String> placeholderKeys = Sets.newHashSet();
|
||||
|
||||
if (!isNormalizedPlaceholder(propertyString) && !isExpressionWithPlaceholder(propertyString)) {
|
||||
return placeholderKeys;
|
||||
}
|
||||
|
||||
Stack<String> stack = new Stack<>();
|
||||
stack.push(propertyString);
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
String strVal = stack.pop();
|
||||
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
|
||||
if (startIndex == -1) {
|
||||
placeholderKeys.add(strVal);
|
||||
continue;
|
||||
}
|
||||
int endIndex = findPlaceholderEndIndex(strVal, startIndex);
|
||||
if (endIndex == -1) {
|
||||
// invalid placeholder?
|
||||
continue;
|
||||
}
|
||||
|
||||
String placeholderCandidate = strVal.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
|
||||
|
||||
// ${some.key:other.key}
|
||||
if (placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)) {
|
||||
stack.push(placeholderCandidate);
|
||||
} else {
|
||||
// some.key:${some.other.key:100}
|
||||
int separatorIndex = placeholderCandidate.indexOf(VALUE_SEPARATOR);
|
||||
|
||||
if (separatorIndex == -1) {
|
||||
stack.push(placeholderCandidate);
|
||||
} else {
|
||||
stack.push(placeholderCandidate.substring(0, separatorIndex));
|
||||
String defaultValuePart =
|
||||
normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex + VALUE_SEPARATOR.length()));
|
||||
if (!Strings.isNullOrEmpty(defaultValuePart)) {
|
||||
stack.push(defaultValuePart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// has remaining part, e.g. ${a}.${b}
|
||||
if (endIndex + PLACEHOLDER_SUFFIX.length() < strVal.length() - 1) {
|
||||
String remainingPart = normalizeToPlaceholder(strVal.substring(endIndex + PLACEHOLDER_SUFFIX.length()));
|
||||
if (!Strings.isNullOrEmpty(remainingPart)) {
|
||||
stack.push(remainingPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return placeholderKeys;
|
||||
}
|
||||
|
||||
private boolean isNormalizedPlaceholder(String propertyString) {
|
||||
return propertyString.startsWith(PLACEHOLDER_PREFIX) && propertyString.endsWith(PLACEHOLDER_SUFFIX);
|
||||
}
|
||||
|
||||
private boolean isExpressionWithPlaceholder(String propertyString) {
|
||||
return propertyString.startsWith(EXPRESSION_PREFIX) && propertyString.endsWith(EXPRESSION_SUFFIX)
|
||||
&& propertyString.contains(PLACEHOLDER_PREFIX);
|
||||
}
|
||||
|
||||
private String normalizeToPlaceholder(String strVal) {
|
||||
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
|
||||
if (startIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
int endIndex = strVal.lastIndexOf(PLACEHOLDER_SUFFIX);
|
||||
if (endIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return strVal.substring(startIndex, endIndex + PLACEHOLDER_SUFFIX.length());
|
||||
}
|
||||
|
||||
private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
|
||||
int index = startIndex + PLACEHOLDER_PREFIX.length();
|
||||
int withinNestedPlaceholder = 0;
|
||||
while (index < buf.length()) {
|
||||
if (StringUtils.substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
|
||||
if (withinNestedPlaceholder > 0) {
|
||||
withinNestedPlaceholder--;
|
||||
index = index + PLACEHOLDER_SUFFIX.length();
|
||||
} else {
|
||||
return index;
|
||||
}
|
||||
} else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) {
|
||||
withinNestedPlaceholder++;
|
||||
index = index + SIMPLE_PLACEHOLDER_PREFIX.length();
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.property;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Apollo Property Sources processor for Spring Annotation Based Application. <br /> <br />
|
||||
* <p>
|
||||
* The reason why PropertySourcesProcessor implements {@link BeanFactoryPostProcessor} instead of
|
||||
* {@link org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor} is that lower versions of
|
||||
* Spring (e.g. 3.1.1) doesn't support registering BeanDefinitionRegistryPostProcessor in ImportBeanDefinitionRegistrar
|
||||
* - {@link com.ctrip.framework.apollo.spring.annotation.ApolloConfigRegistrar}
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered {
|
||||
|
||||
/**
|
||||
* 是否初始化的标识
|
||||
*/
|
||||
private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Spring ConfigurableEnvironment 对象
|
||||
*/
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
//it is safe enough to cast as all known environment is derived from ConfigurableEnvironment
|
||||
this.environment = (ConfigurableEnvironment) environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
// make it as early as possible
|
||||
return Ordered.HIGHEST_PRECEDENCE; // 最高优先级
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.property;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Spring Value 定义
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class SpringValueDefinition {
|
||||
|
||||
/**
|
||||
* KEY
|
||||
*
|
||||
* 即在 Config 中的属性 KEY 。
|
||||
*/
|
||||
private final String key;
|
||||
/**
|
||||
* 占位符
|
||||
*/
|
||||
private final String placeholder;
|
||||
/**
|
||||
* 属性名
|
||||
*/
|
||||
private final String propertyName;
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package cn.iocoder.dashboard.framework.apollox.spring.util;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Bean Registration 工具类
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public class BeanRegistrationUtil {
|
||||
|
||||
// 注册 `beanClass` 到 BeanDefinitionRegistry 中,当且仅当 `beanName` 和 `beanClass` 都不存在对应的 BeanDefinition 时
|
||||
public static boolean registerBeanDefinitionIfNotExists(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass) {
|
||||
// 不存在 `beanName` 对应的 BeanDefinition
|
||||
if (registry.containsBeanDefinition(beanName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 不存在 `beanClass` 对应的 BeanDefinition
|
||||
String[] candidates = registry.getBeanDefinitionNames();
|
||||
for (String candidate : candidates) {
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(candidate);
|
||||
if (Objects.equals(beanDefinition.getBeanClassName(), beanClass.getName())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册 `beanClass` 到 BeanDefinitionRegistry 中
|
||||
BeanDefinition annotationProcessor = BeanDefinitionBuilder.genericBeanDefinition(beanClass).getBeanDefinition();
|
||||
registry.registerBeanDefinition(beanName, annotationProcessor);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.dashboard.framework.apollox.spring.boot.ApolloAutoConfiguration
|
||||
org.springframework.context.ApplicationContextInitializer=\
|
||||
cn.iocoder.dashboard.framework.apollox.spring.boot.ApolloApplicationContextInitializer
|
||||
Loading…
Reference in New Issue