SpringCloud之RefreshScope源码解读

编程

  • Scope与ApplicationContext生命周期

    • AbstractBeanFactory#doGetBean创建Bean实例
  •  

    Copy

    protected <T> T doGetBean(...){ final RootBeanDefinition mbd = ... if (mbd.isSingleton()) { ... } elseif (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

     

    Copy

    @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Scope("refresh") @Documentedpublic@interface RefreshScope { /** * @see Scope#proxyMode() * @return proxy mode */ScopedProxyMode proxyMode()default ScopedProxyMode.TARGET_CLASS; }

    • @Scope 的注册 AnnotatedBeanDefinitionReader#registerBean

     

    Copy

    publicvoidregisterBean(...){ ... ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); ... definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); }

    • 读取@Scope元数据, AnnotationScopeMetadataResolver#resolveScopeMetadata

     

    Copy

    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

     

    Copy

    @Component@ConditionalOnMissingBean(RefreshScope.class) protectedstaticclassRefreshScopeConfigurationimplementsBeanDefinitionRegistryPostProcessor{ ... registry.registerBeanDefinition("refreshScope", BeanDefinitionBuilder.genericBeanDefinition(RefreshScope.class) .setRole(BeanDefinition.ROLE_INFRASTRUCTURE) .getBeanDefinition()); ... }

    • RefreshScope extends GenericScope, 大部分逻辑在 GenericScope 中
    • GenericScope#postProcessBeanFactory 中向AbstractBeanFactory注册自己

     

    Copy

    publicclassGenericScopeimplementsScope, BeanFactoryPostProcessor...{ @OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException { beanFactory.registerScope(this.name/*refresh*/, this/*RefreshScope*/); ... } }

    RefreshScope 刷新过程#

    • 入口在ContextRefresher#refresh

     

    Copy

    publicsynchronized Set<String> refresh(){ Set<String> keys = refreshEnvironment(); this.scope.refreshAll(); return keys; } publicsynchronized 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

     

    Copy

    publicvoidrefreshAll(){ <b>super.destroy();</b> this.context.publishEvent(new RefreshScopeRefreshedEvent()); }

    • ⑨GenericScope#destroy

     

    Copy

    publicvoiddestroy(){ ... Collection<BeanLifecycleWrapper> wrappers = <b>this.cache.clear()</b>; for (BeanLifecycleWrapper wrapper : wrappers) { <b>wrapper.destroy();</b> } }

     

    以上是 SpringCloud之RefreshScope源码解读 的全部内容, 来源链接: utcz.com/z/513379.html

    回到顶部