前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >了解RefreshScope这篇短文就够了

了解RefreshScope这篇短文就够了

原创
作者头像
温安适
修改2020-09-11 18:15:46
4.7K0
修改2020-09-11 18:15:46
举报
文章被收录于专栏:温安适的blog温安适的blog

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简析

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,自定义场景,应使用当前场景的特定ID2.如果底层存储机制没有特定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();
         }
      }
   }
}

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 先加载。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • RefreshScope概述
    • 概述
    • RefreshScope简析
      • Scope的概述
        • 类说明
        • 方法说明
      • GenericScope对Scope的实现
        • get方法
        • Remove方法
      • RefreshScope使用到的Spring的SPI
        • BeanFactoryPostProcessor
        • BeanDefinitionRegistryPostProcessor
        • DisposableBean
        • ApplicationListener
    • 3.七句话总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档