spring-cloud-config动态配置更新原理解读

spring-cloud-config动态配置更新原理解读

首先需要动态刷新的类都加了注解RefreshScope看一下源码:

/**
 * Convenience annotation to put a <code>@Bean</code> definition in
 * {@link org.springframework.cloud.context.scope.refresh.RefreshScope refresh scope}.
 * Beans annotated this way can be refreshed at runtime and any components that are using
 * them will get a new instance on the next method call, fully initialized and injected
 * with all dependencies.
 * 标注了该注解的bean可以动态刷新,刷新后任何调用该组件时都会重新创建实例.
 *
 * @author Dave Syer
 *
 */
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
//自定义的refresh域,spring默认的域有String SCOPE_SINGLETON = "singleton"; String SCOPE_PROTOTYPE = "prototype";
@Documented
public @interface RefreshScope {

	/**
	 * @see Scope#proxyMode()
	 * @return proxy mode
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

执行刷新的时候咱们调用的是:/refresh,他是这样声明的

@Endpoint(id = "refresh")
public class RefreshEndpoint {

	private ContextRefresher contextRefresher;

	public RefreshEndpoint(ContextRefresher contextRefresher) {
		this.contextRefresher = contextRefresher;
	}

	@WriteOperation
	public Collection<String> refresh() {
		Set<String> keys = this.contextRefresher.refresh();
		return keys;
	}

}

从上面看出来,依赖ContextRefresher#refresh操作:

public synchronized Set<String> refresh() {
	Set<String> keys = refreshEnvironment();
	this.scope.refreshAll();
	return keys;
}

下面分两步看,第一步是refreshEnvironment刷新环境信息,第二步是refreshAll信息:

public synchronized Set<String> refreshEnvironment() {
	Map<String, Object> before = extract(
			this.context.getEnvironment().getPropertySources());
	addConfigFilesToEnvironment();
	Set<String> keys = changes(before,
			extract(this.context.getEnvironment().getPropertySources())).keySet();
	this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
	return keys;
}

上面刷新环境,会构建一个新的springApp重新加载一遍配置,然后把配置更新到当前环境当中,并发出环境更新事件

public void refreshAll() {
	super.destroy();
	this.context.publishEvent(new RefreshScopeRefreshedEvent());
}

public void destroy() {
	List<Throwable> errors = new ArrayList<Throwable>();
	Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
	for (BeanLifecycleWrapper wrapper : wrappers) {
		try {
			Lock lock = this.locks.get(wrapper.getName()).writeLock();
			lock.lock();
			try {
				wrapper.destroy();
			}
			finally {
				lock.unlock();
			}
		}
		catch (RuntimeException e) {
			errors.add(e);
		}
	}
	if (!errors.isEmpty()) {
		throw wrapIfNecessary(errors.get(0));
	}
	this.errors.clear();
}

这里将scope域也就是refresh域中的对象都销毁了.

以上已经完成了配置的更新和旧实例的销毁,假如当前有一次调用,
比如,context.getbean(refresh-bean),
会调用到AbstractBeanFactory#doGetBean

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	......省略无关代码

		try {
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			.....省略无关代码

			// Create bean instance.
			if (mbd.isSingleton()) {//判断是不是单列bean,会放到单列scope中存储
				sharedInstance = getSingleton(beanName, () -> {
					try {
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						// Explicitly remove instance from singleton cache: It might have been put there
						// eagerly by the creation process, to allow for circular reference resolution.
						// Also remove any beans that received a temporary reference to the bean.
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

			else if (mbd.isPrototype()) {//判断是不是原型
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);//自定义的@Scope("refresh")存在scopes中
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {//前一步已经销毁了bean实例,这里要重新创建一个bean实例,又因环境信息已经更改,新创建的对象各项属性实现了动态刷新
					Object scopedInstance = scope.get(beanName, () -> {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally {
							afterPrototypeCreation(beanName);
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				...省略无关代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值