Add config change listener feature support . (#220)
parent
02748fc3af
commit
56527b4cf6
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.polaris.config.listener;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A change event when config is changed .
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:iskp.me@gmail.com">Palmer Xu</a> 2022-06-07
|
||||||
|
*/
|
||||||
|
public final class ConfigChangeEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* all changes keys map.
|
||||||
|
*/
|
||||||
|
private final Map<String, ConfigPropertyChangeInfo> changes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* all interested changed keys.
|
||||||
|
*/
|
||||||
|
private final Set<String> interestedChangedKeys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config Change Event Constructor.
|
||||||
|
* @param changes all changes keys map
|
||||||
|
* @param interestedChangedKeys all interested changed keys
|
||||||
|
*/
|
||||||
|
public ConfigChangeEvent(Map<String, ConfigPropertyChangeInfo> changes, Set<String> interestedChangedKeys) {
|
||||||
|
this.changes = changes;
|
||||||
|
this.interestedChangedKeys = interestedChangedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the keys changed.
|
||||||
|
* @return the list of the keys
|
||||||
|
*/
|
||||||
|
public Set<String> changedKeys() {
|
||||||
|
return changes.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific change instance for the key specified.
|
||||||
|
* @param key the changed key
|
||||||
|
* @return the change instance
|
||||||
|
*/
|
||||||
|
public ConfigPropertyChangeInfo getChange(String key) {
|
||||||
|
return changes.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the specified key is changed .
|
||||||
|
* @param key the key
|
||||||
|
* @return true if the key is changed, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isChanged(String key) {
|
||||||
|
return changes.containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maybe subclass override this method.
|
||||||
|
*
|
||||||
|
* @return interested and changed keys
|
||||||
|
*/
|
||||||
|
public Set<String> interestedChangedKeys() {
|
||||||
|
return interestedChangedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.polaris.config.listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuring the change listener interface.
|
||||||
|
*
|
||||||
|
* @author Palmer Xu 2022-05-31
|
||||||
|
*/
|
||||||
|
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,111 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.polaris.config.listener;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||||
|
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.env.MutablePropertySources;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext.fireConfigChange;
|
||||||
|
import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext.initialize;
|
||||||
|
import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext.merge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polaris Config Change Event Listener .
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:iskp.me@gmail.com">Elve.Xu</a> 2022-06-08
|
||||||
|
*/
|
||||||
|
public final class PolarisConfigChangeEventListener implements ApplicationListener<ApplicationEvent> {
|
||||||
|
|
||||||
|
private static final AtomicBoolean started = new AtomicBoolean();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an application event.
|
||||||
|
*
|
||||||
|
* @param event the event to respond to
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(@NonNull ApplicationEvent event) {
|
||||||
|
|
||||||
|
// Initialize application all environment properties .
|
||||||
|
if (event instanceof ApplicationStartedEvent && started.compareAndSet(false, true)) {
|
||||||
|
ApplicationStartedEvent applicationStartedEvent = (ApplicationStartedEvent) event;
|
||||||
|
ConfigurableEnvironment environment = applicationStartedEvent.getApplicationContext().getEnvironment();
|
||||||
|
Map<String, Object> ret = loadEnvironmentProperties(environment);
|
||||||
|
if (!ret.isEmpty()) {
|
||||||
|
initialize(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process Environment Change Event .
|
||||||
|
if (event instanceof EnvironmentChangeEvent) {
|
||||||
|
EnvironmentChangeEvent environmentChangeEvent = (EnvironmentChangeEvent) event;
|
||||||
|
ConfigurableApplicationContext context = (ConfigurableApplicationContext) environmentChangeEvent.getSource();
|
||||||
|
ConfigurableEnvironment environment = context.getEnvironment();
|
||||||
|
Map<String, Object> ret = loadEnvironmentProperties(environment);
|
||||||
|
Map<String, ConfigPropertyChangeInfo> changes = merge(ret);
|
||||||
|
fireConfigChange(changes.keySet(), Maps.newHashMap(changes));
|
||||||
|
changes.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try load all application environment config properties .
|
||||||
|
* @param environment application environment instance of {@link Environment}
|
||||||
|
* @return properties
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Map<String, Object> loadEnvironmentProperties(ConfigurableEnvironment environment) {
|
||||||
|
Map<String, Object> ret = Maps.newHashMap();
|
||||||
|
MutablePropertySources sources = environment.getPropertySources();
|
||||||
|
sources.iterator().forEachRemaining(propertySource -> {
|
||||||
|
Object o = propertySource.getSource();
|
||||||
|
if (o instanceof Map) {
|
||||||
|
for (Map.Entry<String, Object> entry : ((Map<String, Object>) o).entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
String value = environment.getProperty(key);
|
||||||
|
ret.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (o instanceof Collection) {
|
||||||
|
int count = 0;
|
||||||
|
Collection<Object> collection = (Collection<Object>) o;
|
||||||
|
for (Object object : collection) {
|
||||||
|
String key = "[" + (count++) + "]";
|
||||||
|
ret.put(key, object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.polaris.config.example;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.tencent.cloud.polaris.config.annotation.PolarisConfigKVFileChangeListener;
|
||||||
|
import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Config Listener Example .
|
||||||
|
*
|
||||||
|
* @author Palmer Xu 2022-06-06
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public final class PersonConfigChangeListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PolarisConfigKVFileChangeListener Example .
|
||||||
|
* @param event instance of {@link ConfigChangeEvent}
|
||||||
|
*/
|
||||||
|
@PolarisConfigKVFileChangeListener(interestedKeyPrefixes = "teacher")
|
||||||
|
public void onChange(ConfigChangeEvent event) {
|
||||||
|
Set<String> changedKeys = event.changedKeys();
|
||||||
|
|
||||||
|
for (String changedKey : changedKeys) {
|
||||||
|
System.out.printf("%s = %s \n", changedKey, event.getChange(changedKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue