这段时间在对Apollo的学习中,找到了一个不同于Apollo客户端的实现方式。
具体参考视频地址为:分布式配置中心很难?手把手带你从0开始手写一个,走着!
具体demo代码如下:
自定义scope:
package com.DynamicUpdateProperties.Scope
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
/**
* 自定义scope管理bean
*/
@Component
public class RefreshScope implements Scope {
private ConcurrentHashMap map=new ConcurrentHashMap();
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if(map.containsKey(name)){
return map.get(name);
}
//获取到实例
Object object=objectFactory.getObject();
map.put(name,object);
return object;
}
@Override
public Object remove(String name) {
return map.remove(name);
}
@Override
public void registerDestructionCallback(String name, Runnable runnable) {
}
@Override
public Object resolveContextualObject(String name) {
return null;
}
@Override
public String getConversationId() {
return null;
}
}
package com.test.DynamicUpdateProperties.Scope;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;
@Component("com.test.DynamicUpdateProperties.Scope.RefreshScopeRegistry")
public class RefreshScopeRegistry implements BeanDefinitionRegistryPostProcessor {
private BeanDefinitionRegistry beanDefinitionRegistry;
public BeanDefinitionRegistry getBeanDefinitionRegistry() {
return beanDefinitionRegistry;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
this.beanDefinitionRegistry=beanDefinitionRegistry;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
configurableListableBeanFactory.registerScope("jackRefresh",new RefreshScope());
}
}
package com.test.DynamicUpdateProperties;
import com.test.DynamicUpdateProperties.Scope.RefreshScopeRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class PropertiesOperation {
private ConcurrentHashMap map = new ConcurrentHashMap();
BeanDefinitionRegistry beanDefinitionRegistry;
private String scopeName = "jackRefresh";
private Object lock = new Object();
@Autowired
private ConfigurableApplicationContext applicationContext;
@PostConstruct
public void init() {
RefreshScopeRegistry refreshScopeRegistry = (RefreshScopeRegistry) applicationContext.getBean("com.test.DynamicUpdateProperties.Scope.RefreshScopeRegistry");
beanDefinitionRegistry = refreshScopeRegistry.getBeanDefinitionRegistry();
MutablePropertySources mutablePropertySources = applicationContext.getEnvironment().getPropertySources();
OriginTrackedMapPropertySource originTrackedMapPropertySource = new OriginTrackedMapPropertySource("test", map);
mutablePropertySources.addFirst(originTrackedMapPropertySource);
}
public void refreshBean() {
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition(beanDefinitionName);
if (scopeName.equalsIgnoreCase(beanDefinition.getScope())) {
applicationContext.getBeanFactory().destroyScopedBean(beanDefinitionName);
//再次实例化
applicationContext.getBean(beanDefinitionName);
}
}
}
public void refreshEnv(String key, String value) {
MutablePropertySources mutablePropertySources = applicationContext.getEnvironment().getPropertySources();
PropertySource propertySource = mutablePropertySources.get("test");
ConcurrentHashMap collection = (ConcurrentHashMap) propertySource.getSource();
collection.put(key, value);
}
}
测试用Controller
package com.test.DynamicUpdateProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Scope("jackRefresh")
@RestController
public class TestController {
@Autowired
private PropertiesOperation propertiesOperation;
@Autowired
private Environment environment;
@Value("${test.value}")
private String testValue;
@RequestMapping("/test")
public String test() {
System.out.println(this.hashCode()+"");
return testValue;
}
@RequestMapping("/test2")
public String test2(String key) {
System.out.println(this.hashCode()+"");
return environment.getProperty(key);
}
@RequestMapping("/updateEnv")
public String updateEnv(String key, String value) {
try {
propertiesOperation.refreshEnv(key,value);
return "已添加该值";
} catch (Exception exception) {
exception.printStackTrace();
}
return null;
}
@RequestMapping("/updateValue")
public String updateValue() {
try {
propertiesOperation.refreshBean();
return "Value注解属性值已刷新";
} catch (Exception exception) {
exception.printStackTrace();
}
return null;
}
}