了解RefreshScope这篇短文就够了

RefreshScope概述

概述

作用

配置变化时,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

 RefreshScope简析

up-1091e387cbbc9a724f6a6920470e8700efd.png

Scope的概述

类说明

  • ConfigurableBeanFactory使用的策略接口,用于代表Bean的作用域
  • 使用ConfigurableBeanFactory#registerScope(String, Scope)注册自定义的Scope
  • get,remove方法的参数name,在当前Scope中是唯一的
  • Scope的实现,应该是线程安全的

方法说明

方法

是否必须

说明

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,自定义场景,应使用当前场景的特定ID
2.如果底层存储机制没有特定Id,完全可以返回null

GenericScope对Scope的实现 

get方法

包装成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加了同步锁,防止并发访问

Remove方法

从缓存中移除对象

@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();
}

省略其他方法

RefreshScope使用到的Spring的SPI

BeanFactoryPostProcessor

#postProcessBeanFactory注册scope

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
      throws BeansException {
   this.beanFactory = beanFactory;
   beanFactory.registerScope(this.name, this);
   setSerializationId(beanFactory);
}

BeanDefinitionRegistryPostProcessor

#postProcessBeanDefinitionRegistry

如果BeanClass是ScopedProxyFactoryBean.class替换为LockedScopedProxyFactoryBean.class (加了锁)

并设置构造参数的泛型对象为:当前Scope

DisposableBean

#destroy 清空所有Scope下的对象,并且清除缓存

ApplicationListener

# 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();
         }
      }
   }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

bean.getClass()的方法,防止bean是个懒加载的代理对象,确保bean被实例化

3.七句话总结

  • RefreshScope的Bean,是懒代理,当它们被使用(被一个方法调用时)时才初始化,RefreshScope充当了缓存的作用。
  • RefreshScope内部缓存为BeanLifecycleWrapperCache,底层就是ConcurrentHashMap。
  • 缓存的对象是BeanLifecycleWrapper ,bean实例和任何销毁回调(DisposableBean等)的包装器,对bean加了同步锁,防止并发访问。
  • RefreshScope#get 从缓存中获取对象,RefreshScope#remove从缓存中删除对象
  • RefreshScope的父类实现了BeanFactoryPostProcessor,在postProcessBeanFactory 方法中,调用了ConfigurableBeanFactory#registerScope注册了自定义的Scope 
  • RefreshScope在应用上下文中是个bean,通过RefreshScope#refreshAll方法,刷新所有RefreshScope的Bean
  • RefreshScope监听ContextRefreshedEvent事件,会将 所有RefreshScope 先加载。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值