SpringCloud中RefreshScope实现原理

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
因此可以说是形同虚设了-_-|||


版权声明:本文为jy00733505原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。