Spring Cloud @RefreshScope 原理及使用
@RefreshScope那些事 要说清楚RefreshScope,先要了解Scope
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 ... @Scope("refresh") public @interface RefreshScope { ... } @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 refresh() { 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(keys)); this.scope.⑥refreshAll(); } ①提取标准参数(SYSTEM,JNDI,SERVLET)之外所有参数变量 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> } } Spring Cloud Bus 如何触发 Refresh BusAutoConfiguration#BusRefreshConfiguration 发布一个RefreshBusEndpoint @Configuration @ConditionalOnClass({ Endpoint.class,RefreshScope.class }) protected static class BusRefreshConfiguration { @Configuration @ConditionalOnBean(ContextRefresher.class) @ConditionalOnProperty(value = "endpoints.spring.cloud.bus.refresh.enabled",matchIfMissing = true) protected static class BusRefreshEndpointConfiguration { @Bean public RefreshBusEndpoint refreshBusEndpoint(ApplicationContext context,BusProperties bus) { return new RefreshBusEndpoint(context,bus.getId()); } } } RefreshBusEndpoint 会从http端口触发广播RefreshRemoteApplicationEvent事件 @Endpoint(id = "bus-refresh") public class RefreshBusEndpoint extends AbstractBusEndpoint { public void busRefresh() { publish(new RefreshRemoteApplicationEvent(this,getInstanceId(),null)); } } BusAutoConfiguration#refreshListener 负责接收事件(所有配置bus的节点) @Bean @ConditionalOnProperty(value = "spring.cloud.bus.refresh.enabled",matchIfMissing = true) @ConditionalOnBean(ContextRefresher.class) public RefreshListener refreshListener(ContextRefresher contextRefresher) { return new RefreshListener(contextRefresher); } RefreshListener#onApplicationEvent 触发 ContextRefresher public void onApplicationEvent(RefreshRemoteApplicationEvent event) { Set<String> keys = contextRefresher.refresh(); } 大部分需要更新的服务需要打上@RefreshScope,EurekaClient是如何配置更新的 EurekaClientAutoConfiguration#RefreshableEurekaClientConfiguration @Configuration @ConditionalOnRefreshScope protected static class RefreshableEurekaClientConfiguration{ @Bean @RefreshScope public EurekaClient eurekaClient(...) { return new CloudEurekaClient(manager,config,this.optionalArgs,this.context); } @Bean @RefreshScope public ApplicationInfoManager eurekaApplicationInfoManager(...) { ... return new ApplicationInfoManager(config,instanceInfo); } } 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |