作用
配置变化时,RefreshScope的Bean 会被刷新。
应用举例
RefreshScope可以实现,如果数据库的Url(通过Environment)变化时,你可以持有这些连接,使它能够完成他们正在做的事情。之后,下一次从连接池中获取的连接,是使用新的URL。
注: 如果你的DataSource bean是一个HikariDataSource,它不能被刷新。这是 spring.cloud.refresh.never-refreshable的默认值.如果你需要DataSource可以被刷新,请换一个DataSource实现。
如何设置Bean为RefreshScope
要么标注@RefreshScopre,要么在:spring.cloud.refresh.extra-refreshable下指定类名
如何触发
/refresh端点
暴露/refresh端点,你需要添加如下配置
management:
endpoints:
web:
exposure:
include: refresh
方法 | 是否必须 | 说明 |
---|---|---|
Object get(String name, ObjectFactory<?> objectFactory); | 必选 | 1.给定name返回scope下的对象。如果底层存储机制没有找到对象,会使ObjectFactory#getObject()创建2.该方法是Scope的核心方法 |
Object remove(String name); | 可选 | 1.根据name,删除scope下的对象,如果没有找到对象,返回null,否则返回移除的对象 2. 内部不用调用销毁回调方法。应由调用者调用销毁回调 |
void registerDestructionCallback(String name, Runnable callback); | 可选 | 1.注册一个回调,用于销毁在Scope内指定的对象(或销毁整个Scope)2.在DisposableBean, destroy-method, DestructionAwareBeanPostProcessor等中调用3.销毁是指,scope生命周期内自动销毁,不是scoped 对象被application显示移除4.如果scoped对象,被#remove 方法移除,任何注册的销毁回调都应该被移除 |
Object resolveContextualObject(String key); | 可选 | 通过key,解析上下文对象 |
String getConversationId(); | 可选 | 1.返回当前Scope下的会话Id,自定义场景,应使用当前场景的特定ID2.如果底层存储机制没有特定Id,完全可以返回null |
包装成BeanLifecycleWrapper 放入缓存。Locks的中加入当前name对应的锁。从BeanLifecycleWrapper 返回对象。
@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;
}
}
BeanLifecycleWrapper说明
bean实例和任何销毁回调(DisposableBean等)的包装器,对bean加了同步锁,防止并发访问
从缓存中移除对象
@Override
public Object remove(String name) {
BeanLifecycleWrapper value = this.cache.remove(name);
if (value == null) {
return null;
}
// Someone might have added another object with the same key, but we
// keep the method contract by removing the
// value we found anyway
return value.getBean();
}
省略其他方法
#postProcessBeanFactory注册scope
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
this.beanFactory = beanFactory;
beanFactory.registerScope(this.name, this);
setSerializationId(beanFactory);
}
#postProcessBeanDefinitionRegistry
如果BeanClass是ScopedProxyFactoryBean.class替换为LockedScopedProxyFactoryBean.class (加了锁)
并设置构造参数的泛型对象为:当前Scope
#destroy 清空所有Scope下的对象,并且清除缓存
# onApplicationEvent
监听ContextRefreshedEvent事件,会将 所有RefreshScope 先加载
public void onApplicationEvent(ContextRefreshedEvent event) {
start(event);
}
public void start(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.context && this.eager
&& this.registry != null) {
eagerlyInitialize();
}
}
private void eagerlyInitialize() {
for (String name : this.context.getBeanDefinitionNames()) {
BeanDefinition definition = this.registry.getBeanDefinition(name);
if (this.getName().equals(definition.getScope())
&& !definition.isLazyInit()) {
Object bean = this.context.getBean(name);
if (bean != null) {
bean.getClass();
}
}
}
}
bean.getClass()的方法,防止bean是个懒加载的代理对象,确保bean被实例化
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。