2023-09-15
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105775039

RefreshScope注解类实例化基本流程

202309152316376271.png

nacos如何通过RefreshScope注解进行属性刷新

RefreshScope注解原理说了几篇,接着这篇文章的刷新问题。回到NacosContextRefresherregisterNacosListener来,在接受到有配置修改的情况下,会进行监听器通知,然后这里面会进行RefreshEvent事件的通知:

202309152316387452.png

RefreshEventListener的handle

主要是在RefreshEventListener这个监听器进行环境属性源的刷新,以及scope被代理对象缓存的释放。具体来看下这么做的。

202309152316395493.png

ContextRefresher的refresh

其实这个里面的scopeRefreshScope对象,scope被代理缓存失效就是靠他的,但是前面会先进行环境的刷新,为什么呢,因为需要刷新属性配置源,才可以刷新属性配置对象ConfigurationProperties属性,才可以在创建被代理对象的时候进行属性注入和配置属性对象的属性绑定。

    	public synchronized Set<String> refresh() {
    		Set<String> keys = refreshEnvironment();//刷新环境属性源
    		this.scope.refreshAll();//刷新的地方
    		return keys;
    	}

refreshEnvironment

这里做的就是先获取老的配置属性源,然后刷新配置属性,然后比对新的和老的区别,获取有改变的属性源key集合返回。

    	public synchronized Set<String> refreshEnvironment() {
    		Map<String, Object> before = extract(
    				this.context.getEnvironment().getPropertySources());//获取老的配置属性源
    		addConfigFilesToEnvironment();//刷新配置文件
    		Set<String> keys = changes(before,//获取修改的属性源key
    				extract(this.context.getEnvironment().getPropertySources())).keySet();
    		//通知事件,通知配置属性对象去重新加载属性
    		this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
    		return keys;
    	}
addConfigFilesToEnvironment

这里就开启了一个新的上下文,然后用监听事件去加载新配置,然后替换掉老的。

    /* For testing. */ ConfigurableApplicationContext addConfigFilesToEnvironment() {
    		ConfigurableApplicationContext capture = null;
    		try {
    			//创建新的环境去接受新配置
    			StandardEnvironment environment = copyEnvironment(
    					this.context.getEnvironment());
    			//创建新的环境去加载配置
    			SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class)
    					.bannerMode(Mode.OFF).web(WebApplicationType.NONE)
    					.environment(environment);
    			
    			//添加跟配置文件加载有关的
    			builder.application()
    					.setListeners(Arrays.asList(new BootstrapApplicationListener(),
    							new ConfigFileApplicationListener()));
    			capture = builder.run();
    			if (environment.getPropertySources().contains(REFRESH_ARGS_PROPERTY_SOURCE)) {
    				environment.getPropertySources().remove(REFRESH_ARGS_PROPERTY_SOURCE);
    			}
    			MutablePropertySources target = this.context.getEnvironment()
    					.getPropertySources();
    			String targetName = null;
    			for (PropertySource<?> source : environment.getPropertySources()) {
    				String name = source.getName();
    				if (target.contains(name)) {
    					targetName = name;
    				}
    				if (!this.standardSources.contains(name)) {
    					if (target.contains(name)) {
    						//有同名的就替换老的属性源
    						target.replace(name, source);
    					}
    					else {
    						if (targetName != null) {
    							target.addAfter(targetName, source);
    						}
    						else {
    							// targetName was null so we are at the start of the list
    							target.addFirst(source);
    							targetName = name;
    						}
    					}
    				}
    			}
    		}
    		finally {
    			ConfigurableApplicationContext closeable = capture;
    			...
    		}
    		return capture;
    	}
changes获取新老之间有差异的属性源key集合

进行每个属性源key的比较,然后取出不同的。

    private Map<String, Object> changes(Map<String, Object> before,
    			Map<String, Object> after) {
    		Map<String, Object> result = new HashMap<String, Object>();
    		for (String key : before.keySet()) {
    			if (!after.containsKey(key)) {
    				result.put(key, null);
    			}
    			else if (!equal(before.get(key), after.get(key))) {
    				result.put(key, after.get(key));
    			}
    		}
    		for (String key : after.keySet()) {
    			if (!before.containsKey(key)) {
    				result.put(key, after.get(key));
    			}
    		}
    		return result;
    	}

还有通知和scope刷新没说,后面讲。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵

阅读全文