SpringCloud@RefreshScope原理及使⽤
@RefreshScope那些事
要说清楚RefreshScope,先要了解Scope
Scope(org.springframework.fig.Scope)是Spring 2.0开始就有的核⼼的概念
RefreshScope(org.fresh)是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 = Scope();
final Scope scope = (scopeName);
Object scopedInstance = (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 = solveScopeMetadata(abd);
abd.ScopeName());
...
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, istry);
}
读取@Scope元数据, AnnotationScopeMetadataResolver#resolveScopeMetadata
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
if (attributes != null) {
metadata.String("value"));
ScopedProxyMode proxyMode = Enum("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{
...
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
.getBeanDefinition());
...
}
RefreshScope extends GenericScope, ⼤部分逻辑在 GenericScope 中
GenericScope#postProcessBeanFactory 中向AbstractBeanFactory注册⾃⼰
public class GenericScope implements Scope, {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
...
}
}
RefreshScope 刷新过程
⼊⼝在ContextRefresher#refresh
refresh() {
Map<String, Object> before = ①extract(
②addConfigFilesToEnvironment();
Set<String> keys = ④changes(before,
③t.getEnvironment().getPropertySources())).keySet();
this.scope.⑥refreshAll();
}
①提取标准参数(SYSTEM,JNDI,SERVLET)之外所有参数变量
②把原来的Environment⾥的参数放到⼀个新建的Spring Context容器下重新加载,完事之后关闭新容器
③提起更新过的参数(排除标准参数)
④⽐较出变更项
⑤发布环境变更事件,接收:EnvironmentChangeListener/LoggingRebinder
⑥RefreshScope⽤新的环境参数重新⽣成Bean
重新⽣成的过程很简单,清除refreshscope缓存幷销毁Bean,下次就会重新从BeanFactory获取⼀个新的实例(该实例使⽤新的配置)
RefreshScope#refreshAll
public void refreshAll() {
<b>super.destroy();</b>
}
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.abled", matchIfMissing = true)  protected static class BusRefreshEndpointConfiguration {
@Bean
public RefreshBusEndpoint refreshBusEndpoint(ApplicationContext context,
BusProperties bus) {
return new RefreshBusEndpoint(context, Id());
}
}
}
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.abled", 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 = fresh();
}
⼤部分需要更新的服务需要打上@RefreshScope, EurekaClient是如何配置更新的EurekaClientAutoConfiguration#RefreshableEurekaClientConfigurationspringcloud怎么读音
@Configuration
@ConditionalOnRefreshScope
protected static class RefreshableEurekaClientConfiguration{
@Bean
@RefreshScope
public EurekaClient eurekaClient(...) {
return new CloudEurekaClient(manager, config, this.optionalArgs,
}
@Bean
@RefreshScope
public ApplicationInfoManager eurekaApplicationInfoManager(...) {
...
return new ApplicationInfoManager(config, instanceInfo);
}
}
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。