SpringCloud之RefreshScope

@Scope 源码解读

  • Scope(org.springframework.beans.factory.config.Scope)是Spring 2.0开始就有的核心的概念

  • RefreshScope(org.springframework.cloud.context.scope.refresh)是spring cloud提供的一种特殊的scope实现,用来实现配置、实例热加载。

  • Scope -> GenericScope -> RefreshScope

  • Scope与ApplicationContext生命周期

    • AbstractBeanFactory#doGetBean创建Bean实例
protected <T> T doGetBean(...){
final RootBeanDefinition mbd = ...
if (mbd.isSingleton()) {
...
} else if (mbd.isPrototype())
...
} else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {...});
...
}
...
}
  • Singleton和Prototype是硬编码的,并不是Scope子类。 Scope实际上是自定义扩展的接口
  • Scope Bean实例交由Scope自己创建,例如SessionScope是从Session中获取实例的,ThreadScope是从ThreadLocal中获取的,而RefreshScope是在内建缓存中获取的
  • @Scope 对象的实例化
    • @RefreshScope 是scopeName="refresh"的 @Scope
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope { /**
* @see Scope#proxyMode()
* @return proxy mode
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
  • @Scope 的注册 AnnotatedBeanDefinitionReader#registerBean
public void registerBean(...){
...
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
...
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
}
  • 读取@Scope元数据, AnnotationScopeMetadataResolver#resolveScopeMetadata
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), Scope.class);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
  • Scope实例对象通过ScopedProxyFactoryBean创建,其中通过AOP使其实现ScopedObject接口,这里不再展开

@RefreshScope 源码解读

RefreshScope注册

  • RefreshAutoConfiguration#RefreshScopeConfiguration
@Component
@ConditionalOnMissingBean(RefreshScope.class)
protected static class RefreshScopeConfiguration implements BeanDefinitionRegistryPostProcessor{
...
registry.registerBeanDefinition("refreshScope",
BeanDefinitionBuilder.genericBeanDefinition(RefreshScope.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
.getBeanDefinition());
...
}
  • RefreshScope extends GenericScope, 大部分逻辑在 GenericScope 中
  • GenericScope#postProcessBeanFactory 中向AbstractBeanFactory注册自己
public class GenericScope implements Scope, BeanFactoryPostProcessor...{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
beanFactory.registerScope(this.name/*refresh*/, this/*RefreshScope*/);
...
}
}

RefreshScope 刷新过程

  • 入口在ContextRefresher#refresh
public synchronized Set<String> refresh() {
Set<String> keys = refreshEnvironment();
this.scope.refreshAll();
return keys;
} public synchronized Set<String> refreshEnvironment() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
return keys;
}
  • ①提取标准参数(SYSTEM,JNDI,SERVLET)之外所有参数变量
  • ②把原来的Environment里的参数放到一个新建的Spring Context容器下重新加载,完事之后关闭新容器
  • ③提起更新过的参数(排除标准参数)
  • ④比较出变更项
  • ⑤发布环境变更事件,接收:EnvironmentChangeListener/LoggingRebinder
  • ⑥RefreshScope用新的环境参数重新生成Bean
  • ⑦重新生成的过程很简单,清除refreshscope缓存幷销毁Bean,下次就会重新从BeanFactory获取一个新的实例(该实例使用新的配置)
  • ⑧RefreshScope#refreshAll
public void refreshAll() {
<b>super.destroy();</b>
this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
  • ⑨GenericScope#destroy
public void destroy() {
...
Collection<BeanLifecycleWrapper> wrappers = <b>this.cache.clear()</b>;
for (BeanLifecycleWrapper wrapper : wrappers) {
<b>wrapper.destroy();</b>
}
}

SpringCloud之RefreshScope 源码解读的更多相关文章

  1. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  2. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  3. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  4. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  5. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  6. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

  7. SDWebImage源码解读之SDWebImageCache(下)

    第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...

  8. AFNetworking 3.0 源码解读 总结(干货)(下)

    承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...

  9. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

随机推荐

  1. Java第三次作业第二题

    2. [请复制本程序,作为java程序代码,进行编译,补充填写缺失代码部分,并实现题目要求功能,从而获得空白填写所需的内容.] 定义3个线程,模拟红绿灯的效果 一个线程控制画一个实心红圆 一个线程控制 ...

  2. NPOI导出数值格式设置(我是保留四位小数,不足补0)

    看了网上好多帖子,都是保留两位小数的,写法是: HSSFDataFormat.GetBuiltinFormat("0.00"); 于是想四位小数,就是多加两个00,变成: HSSF ...

  3. uni-app开发微信小程序的几天时间

    人只有在不断的学习,才能不断的给自己充电,如果我们停止了学习,就像人没有了血脉,就会死亡,近来学习比较忙,压力比较大,整天面对着电脑,敲击代码,从中虽然收获了快乐,但是换来的确实身体的伤痛,最近虽然自 ...

  4. C++基础之string类

    string也是属于顺序容器,但是string类很重要且经常使用,因此在这里单独记录. string的操作总结 string(const char *s,int n);  //用c字符串s初始化,s应 ...

  5. windows导出文件名列表

    新建txt文件,粘贴以下命令: DIR *.*  /B >LIST.TXT 将txt文件的后缀改为.bat 执行bat文件即可

  6. filebeat使用multiline丢失数据问题

    最近部署filebeat采集日志. 发现配置multiline后,日志偶尔会丢失数据,而且采集到的数据长度都不相同,所以和日志长度没有关系. 查阅filebeat官网后,找到了问题.filebeat有 ...

  7. 挖穿各大SRC的短信轰炸

    今天给大家分享一个短信轰炸绕过的姿势,大疆.百度.腾讯等等src都有用此方法绕过的案例. 给大家看一下 这里就不给大家截图了,在src中提交的截图都没有打码,这里放出来不太方便. 这里就只举出大疆的例 ...

  8. IT修养-基础篇

    1.科学基础 成为开发人员的过程不尽相同,有的是科班出身,有的是兴趣爱好,还有的是专业机构的培训,在这个过程中,可能全面或者零散甚至没有学习过计算机基础学科,但无论是哪一种,想要成为更高层次的开发人员 ...

  9. Python 爬虫监控女神的QQ空间新的说说,实现秒赞,并发送说说内容到你的邮箱

    这个文章主要是在前一篇文章上新增了说说秒赞的功能 前一篇文章可以了解一下 那么,这次主要功能就是 监控女神的 QQ空间,一旦女神发布新的说说,马上点赞,你的邮箱马上就会收到说说内容,是不是想了解一下 ...

  10. uptimerobot 监控

    前言 由于搞了多个公共服务于多台vps,需要监控项目稳定性与服务器稳定性,考察了阿里云云监控与uptimerobot,最后选择了uptimerobot 教程 访问官网,注册账号 : https://u ...