@RefreshScope动态刷新原理

1、@RefreshScope 的作用

@RefreshScope 用于标记一个 Bean,使其在配置发生变化时能够动态刷新;例如,当应用从配置中心(如 Spring Cloud Config、Nacos)获取到新的配置后,标记了 @RefreshScope 的 Bean 会被销毁并重新创建,从而加载新的配置值。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {

	/**
	 * Alias for {@link Scope#proxyMode}.
	 * @see Scope#proxyMode()
	 * @return proxy mode
	 */
	@AliasFor(annotation = Scope.class)
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

2、@RefreshScope 的实现原理

底层基于 Spring 的 Bean Scope 扩展机制 和 事件驱动模型,Spring 提供了自定义 Scope 的能力,@RefreshScope 就是通过自定义 Scope 实现的。

2.1 RefreshScope 的 Scope 机制

@RefreshScope 对应的 Scope 是 RefreshScope,它是 Spring Cloud 提供的一个自定义 Scope。当 Bean 被标记为 @RefreshScope 时,Spring 会将其放入 RefreshScope 中管理。当配置发生变化时,RefreshScope 会销毁这些 Bean,Spring 容器会重新创建它们,从而加载新的配置。

2.2 配置刷新的触发

配置刷新的触发通常是通过 RefreshEndpoint 或 RefreshEventListener (配置中心)的通知机制。当配置发生变化时,会调用 ContextRefresher#refresh() 方法,触发 RefreshScope#refreshAll() 的刷新逻辑。

3、核心类

RefreshScope

public class RefreshScope extends GenericScope
		implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, Ordered {
	// 其他方法省略...	
	@ManagedOperation(description = "Dispose of the current instance of all beans "
			+ "in this scope and force a refresh on next method execution.")
	public void refreshAll() {
		// 清空缓存,触发 Bean 重新创建
		super.destroy();
		this.context.publishEvent(new RefreshScopeRefreshedEvent());
	}
}

ContextRefresher

刷新上下文,当配置发生变化时触发调用RefreshScope#refreshAll()实现刷新

public abstract class ContextRefresher {
	//其他方法省略...
	private RefreshScope scope;
	public synchronized Set<String> refresh() {
		Set<String> keys = refreshEnvironment();
		this.scope.refreshAll();
		return keys;
	}
}

GenericScope

RefreshScope的父类,管理RefreshScope范围的 Bean 的缓存和生命周期
get方法创建bean和缓存

public class GenericScope
	implements Scope, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, DisposableBean {
	private BeanLifecycleWrapperCache cache = new BeanLifecycleWrapperCache(new StandardScopeCache());
	
		@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		BeanLifecycleWrapper value = this.cache.put(name, new BeanLifecycleWrapper(name, objectFactory));
		this.locks.putIfAbsent(name, new ReentrantReadWriteLock());
		try {
			return value.getBean();
		}
		catch (RuntimeException e) {
			this.errors.put(name, e);
			throw e;
		}
	}
}

AbstractBeanFactory

AbstractBeanFactory 是 Spring 容器中管理 Bean 的核心类之一。它负责创建和管理 Bean 实例,并处理不同作用域的 Bean。
AbstractBeanFactory#doGetBean

    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
		//省略其他代码...
		if (mbd.isSingleton()){
			//省略其他代码...
		}else if (mbd.isPrototype()) {
			//省略其他代码...
		} else {
			String scopeName = mbd.getScope();
            if (!StringUtils.hasLength(scopeName)) {
                throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
            }

            Scope scope = (Scope)this.scopes.get(scopeName);
            if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope name '" + 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;
                });
                beanInstance = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            } catch (IllegalStateException var32) {
                throw new ScopeNotActiveException(beanName, scopeName, var32);
            }
		}
	}

RefreshEventListener

RefreshEventListener 监听配置刷新事件,并触发 RefreshScope 中的 Bean 重新加载

public class RefreshEventListener implements SmartApplicationListener {

	private static Log log = LogFactory.getLog(RefreshEventListener.class);

	private ContextRefresher refresh;

	private AtomicBoolean ready = new AtomicBoolean(false);

	public RefreshEventListener(ContextRefresher refresh) {
		this.refresh = refresh;
	}

	@Override
	public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
		return ApplicationReadyEvent.class.isAssignableFrom(eventType)
				|| RefreshEvent.class.isAssignableFrom(eventType);
	}

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationReadyEvent) {
			handle((ApplicationReadyEvent) event);
		}
		else if (event instanceof RefreshEvent) {
			handle((RefreshEvent) event);
		}
	}

	public void handle(ApplicationReadyEvent event) {
		this.ready.compareAndSet(false, true);
	}

	public void handle(RefreshEvent event) {
		if (this.ready.get()) { // don't handle events before app is ready
			log.debug("Event received " + event.getEventDesc());
			Set<String> keys = this.refresh.refresh();
			log.info("Refresh keys changed: " + keys);
		}
	}

}

RefreshEndpoint

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

	private static final Log LOG = LogFactory.getLog(RefreshEndpoint.class);

	private final ContextRefresher contextRefresher;

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

	@WriteOperation
	public Collection<String> refresh() {
		Set<String> keys = this.contextRefresher.refresh();
		LOG.info("Refreshed keys : " + keys);
		return keys;
	}

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值