实现思路
-
所有的配置数据(xx.properties,xx.yml)都存储在环境变量Environment中,更改配置其实就是更改Environment中的属性值。
-
在单例bean中的@Value注解配置的属性值如何实现动态更新?单例bean只创建了一次,其余取值都是从singleObjects缓存中拿取。
如何解决这个问题?当然可以用多例,我们也可以自定义Scope。
-
更新完Environment环境变量以后,刷新带有我们自定义Scope的BeanDefinition,重新创建bean。
-
如何自定义Scope?如何获取带有自定义Scope的BeanDefinition?
自定义Scope
-
实现Scope接口
public class RefreshConfigScope implements Scope { //缓存实例 private final ConcurrentHashMap<String,Object> caches=new ConcurrentHashMap<>(); @Override public Object get(String s, ObjectFactory<?> objectFactory) { if(caches.containsKey(s)){ return caches.get(s); } //getObject(),钩子方法创建实例 Object object = objectFactory.getObject(); caches.put(s,object); return object; } @Override public Object remove(String s) { return caches.remove(s); } @Override public void registerDestructionCallback(String s, Runnable runnable) { } @Override public Object resolveContextualObject(String s) { return null; } @Override public String getConversationId() { return null; } }objectFactory.getObject()调用是在AbstractBeanFactory.doGetBean()
String scopeName = mbd.getScope(); //scopeName为我们自定义的名称,后面会讲 Scope scope = (Scope)this.scopes.get(scopeName); try { //创建实例,钩子方法的调用 Object scopedInstance = scope.get(beanName, () -> { this.beforePrototypeCreation(beanName); Object var4; try { var4 = this.createBean(beanName, mbd, args); } finally { this.afterPrototypeCreation(beanName); } return var4; }); bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException var23) { } -
Scope注册到Spring中
实现BeanDefinitionRegistryPostProcessor接口
public class RefreshConfigScopeRegistry implements BeanDefinitionRegistryPostProcessor { //beanDefinitionRegistry可以管理所有的BeanDefinition private BeanDefinitionRegistry beanDefinitionRegistry; @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { this.beanDefinitionRegistry=beanDefinitionRegistry; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { //注册自定义的Scope,name="RefreshConfig" configurableListableBeanFactory.registerScope("RefreshConfig",new RefreshConfigScope()); } public BeanDefinitionRegistry getBeanDefinitionRegistry() { return beanDefinitionRegistry; } }
配置动态更新
-
创建自定义的环境变量PropertySource
//创建redis-propertySources 环境资源 private void createRedisSpringProperty() { MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); //redisSourceName:配置文件名称,map =new ConcurrentHashMap(),以map数据结构存储 OriginTrackedMapPropertySource redisSource = new OriginTrackedMapPropertySource(redisSourceName, map); propertySources.addFirst(redisSource); } -
从redis中查询配置数据-写入自定义的环境变量中
try { //redisConfigKey在redis中配置主键 properties = redisTemplate.opsForHash().entries(redisConfigKey); } catch (Exception e) { logger.error("load config from redis fail,reason:"+e.getMessage()); } if (properties.isEmpty()) return; MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); //redisSourceName自定义的propertySources名称 PropertySource<?> source = propertySources.get(redisSourceName); ConcurrentHashMap concurrentHashMap = (ConcurrentHashMap) source.getSource(); concurrentHashMap.clear(); Set<Object> keys = properties.keySet(); //遍历并写入环境变量中 for (Object key : keys) { concurrentHashMap.put(key, properties.get(key)); } -
刷新带有自定义Scope的bean
//更新@Value 相关属性值 private void refreshBean() { String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { //beanDefinitionRegistry获得beanDefinition BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition(name); //判断是否是自定义Scope if (scopeName.equals(beanDefinition.getScope())) { //销毁bean applicationContext.getBeanFactory().destroyScopedBean(name); //重新实例化 applicationContext.getBean(name); } } }
78

被折叠的 条评论
为什么被折叠?



