SpringCloud中RefreshScope实现原理
jar包版本
- spring-cloud-context 2.0.0.RELEASE
scope基础理论
RefreshScope是springCloud在Scope的基础上实现的,因此先了解一下Scope的实现原理。
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly){
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>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
}
}
spring在获取bean实例的时候会先判断这个bean是单例的还是原型的或者其他类型的(session,request以及其他自定义scope)。这里通过源码我们可以看到
实际上如果是自定义的scope,spring会调用scope的get方法来实现bean的获取,其逻辑交给了scope子类自己去实现。那么首先spring是在什么时候或者说怎么
获取到自定义的scopes的实例集合呢
public class GenericScope implements Scope, BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor, DisposableBean {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
this.beanFactory = beanFactory;
beanFactory.registerScope(this.name, this);
setSerializationId(beanFactory);
}
}
因为RefreshScope继承自GenericScope,而GenericScope又实现了BeanFactoryPostProcessor,因此在IOC容器生命周期postProcessBeanFactory时,就
将所有继承GenericScope的scope注册到了BeanFactory的scopes中。
最后再来看看RefreshScope到底是怎么来实现配置的刷新的。
@ManagedResource
public class RefreshScope extends GenericScope implements ApplicationContextAware, Ordered {
@ManagedOperation(description = "Dispose of the current instance of bean name provided and force a refresh on next method execution.")
public boolean refresh(String name) {
if (!name.startsWith(SCOPED_TARGET_PREFIX)) {
name = SCOPED_TARGET_PREFIX + name;
}
if (super.destroy(name)) {
this.context.publishEvent(new RefreshScopeRefreshedEvent(name));
return true;
}
return false;
}
@ManagedOperation(description = "Dispose of the current instance of all beans in this scope and force a refresh on next method execution.")
public void refreshAll() {
super.destroy();
this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
}
看了源码可以发现,springcloud其实将整个bean都注册到了mbean上,因此可以通过外部来直接调用其方法,如health就是通过refrsh接口调用的这里
的refresh方法。而refresh方法是调用了GenericScope的销毁方法,去掉了缓存中的bean。在spring下次调用getbean的时候由于缓存中之前创建的
bean实例已经被销毁,因此会重新创建bean。从而达到了刷新配置的目的。
总结
refreshScope通过scope提供的扩展机制实现了bean的重新创建,而又将重新创建的实际交给了mbean来控制。因此达到了可以运行时动态修改配置文件的效果
比如EurekaClient。PS:我其实是在自己项目的EurekaClient上看到了这个注解才去看了下它的实现原理。然而看完之后发现项目并没有使用spring的actuate
因此可以说是形同虚设了-_-|||