目录
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;
}
}