SpringCloud@RefreshScope实现原理原来这么简单
环境:spring cloud context2.2.8.RELEASE + spring boot 2.3.9.RELEASE
1 RefreshScope源码
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {
/**
* @see Scope#proxyMode()
* @return proxy mode
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
该注解上添加了@Scope("refresh")注解指明了作⽤域名为refresh。
2 注册RefreshScope
public class RefreshAutoConfiguration {
/**
* Name of the refresh scope name.
*/
public static final String REFRESH_SCOPE_NAME = "refresh";
// 注册RefreshScope
@Bean
@ConditionalOnMissingBean(RefreshScope.class)
public static RefreshScope refreshScope() {
return new RefreshScope();
}
// 主要功能是刷新配置⽂件,发布事件(事件监听程序接收到事件后会重写配置相关的配置类)
@Bean
@ConditionalOnMissingBean
public ContextRefresher contextRefresher(ConfigurableApplicationContext context, RefreshScope scope) {
return new ContextRefresher(context, scope);
}
// 监听上下⽂刷新事件
@Bean
public RefreshEventListener refreshEventListener(ContextRefresher contextRefresher) {
return new RefreshEventListener(contextRefresher);
}
}
RefreshScope类
该类的核⼼⽅法都在⽗类中实现
public class RefreshScope extends GenericScope implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, Ordered {
public boolean refresh(String name) {
if (!name.startsWith(SCOPED_TARGET_PREFIX)) {
name = SCOPED_TARGET_PREFIX + name;
}
if (super.destroy(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();
}
}
该类继承⾃GenericScope,⽽GenericScope继承BeanFactoryPostProcessor。
public class GenericScope implements Scope, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, DisposableBean {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
setSerializationId(beanFactory);
}
}
在这⾥会注册RefreshScope。注册的Scope将会在AbstractBeanFactory#doGetBean⽅法中调⽤,该⽅法中会先拿到当前BeanDefinition中定义的Scope,通过scopeName从Map集合中拿到Scope类,最后调⽤Scope的get⽅法获取实例对象;详细参见15例,查看get⽅法调⽤时机。
添加了@RefreshScope注解的Bean对象会执⾏RefreshScope#get⽅法
public class GenericScope implements Scope, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, DisposableBean {
private BeanLifecycleWrapperCache cache = new BeanLifecycleWrapperCache(new StandardScopeCache());
// 将要获取的Bean缓存上
public Object get(String name, ObjectFactory<?> objectFactory) {
BeanLifecycleWrapper value = this.cache.put(name, new BeanLifecycleWrapper(name, objectFactory));
this.locks.putIfAbsent(name, new ReentrantReadWriteLock());
try {
Bean();
} catch (RuntimeException e) {
throw e;
}
}
}
3 Refresh端点触发时机
触发机制基于事件驱动,发布EnvironmentChangeEvent事件。
当调⽤/actuator/refresh端点时,执⾏如下refresh:
@Endpoint(id = "refresh")
public class RefreshEndpoint {
private ContextRefresher contextRefresher;
@WriteOperation
public Collection<String> refresh() {
Set<String> keys = fresh();
return keys;
}
}
调⽤ContextRefresher#refresh⽅法
public class ContextRefresher {
public synchronized Set<String> refresh() {
Set<String> keys = refreshEnvironment();
freshAll();
return keys;
}
public synchronized Set<String> refreshEnvironment() {
// 配置信息修改之前的值
Map<String, Object> before = t.getEnvironment().getPropertySources());
// 重新加载读取配置信息
addConfigFilesToEnvironment();
// 获取所有改变的配置
Set<String> keys = changes(before, t.getEnvironment().getPropertySources())).keySet();
// 发布事件(处理事件中所有配置类@ConfigurationProperties)
return keys;
}
}
在refreshEnvironment⽅法中会发布⼀个EnvironmentChangeEvent事件;查看该事件的
public class ConfigurationPropertiesRebinder implements ApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {
private ConfigurationPropertiesBeans beans;
private ApplicationContext applicationContext;
private Map<String, Exception> errors = new ConcurrentHashMap<>();
public ConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {
this.beans = beans;
}
@ManagedOperation
public void rebind() {
// 遍历所有的配置类(带有@ConfigurationProperties注解的类)
for (String name : BeanNames()) {
/
/ 对每⼀个bean进⾏重新绑定
rebind(name);
}
}
@ManagedOperation
public boolean rebind(String name) {
if (!BeanNames().contains(name)) {
return false;
}
if (this.applicationContext != null) {
Object bean = Bean(name);
if (AopUtils.isAopProxy(bean)) {
bean = TargetObject(bean);
}
if (bean != null) {
if (getNeverRefreshable().Class().getName())) {
return false; // ignore
}
// 销毁当前的bean
AutowireCapableBeanFactory().destroyBean(bean);
// 初始化Bean
AutowireCapableBeanFactory().initializeBean(bean, name);
return true;
}
}
return false;
}
@ManagedAttribute
public Set<String> getBeanNames() {
return new HashSet<>(BeanNames());
}
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
if (this.applicationContext.Source()) || Keys().Source())) {
rebind();
}
}
}
当收到EnvironmentChangeEvent事件后执⾏rebind⽅法。在该类中的beans是通过构造函数传过来的,接下来先查看这个对象是如何被构造的public class ConfigurationPropertiesRebinderAutoConfiguration implements ApplicationContextAware, SmartInitializingSingleton {
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public static ConfigurationPropertiesBeans configurationPropertiesBeans() {
return new ConfigurationPropertiesBeans();
}
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public ConfigurationPropertiesRebinder configurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {
ConfigurationPropertiesRebinder rebinder = new ConfigurationPropertiesRebinder(beans);
return rebinder;
}
}
在这个⾃动配置类中创建了
ConfigurationPropertiesRebinder并且将ConfigurationPropertiesBeans 注⼊。ConfigurationPropertiesBeans是个BeanPostProcessor处理器@Component
public class ConfigurationPropertiesBeans
implements BeanPostProcessor, ApplicationContextAware {
// 添加有@ConfigurationProperties注解的bean都将保存在该集合中
private Map<String, ConfigurationPropertiesBean> beans = new HashMap<>();
private ApplicationContext applicationContext;
private ConfigurableListableBeanFactory beanFactory;
private String refreshScope;
private boolean refreshScopeInitialized;
private ConfigurationPropertiesBeans parent;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (isRefreshScoped(beanName)) {
ConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean
.get(this.applicationContext, bean, beanName);
if (propertiesBean != null) {
this.beans.put(beanName, propertiesBean);
}
return bean;
}
private boolean isRefreshScoped(String beanName) {
if (freshScope == null && !freshScopeInitialized) {
for (String scope : RegisteredScopeNames()) {
if (RegisteredScope(
scope) instanceof org.fresh.RefreshScope) {
break;
}
}
}
if (beanName == null || freshScope == null) {
return false;
}
return ainsBeanDefinition(beanName) && freshScope.equals(BeanDefinition(beanName).getScope());
}
public Set<String> getBeanNames() {
return new HashSet<String>(this.beans.keySet());
}
}
该BeanPostProcessor的
postProcessBeforeInitialization⽅法执⾏在初始化bean的时候执⾏在这⾥就会判断当前的Bean是否是RefreshScope Bean。
在isRefreshScoped⽅法中遍历注册的所有Scope并且判断是否是有RefreshScope,先从注册的所有Scope中查RefreshScope,如果没有返回false,如果是则返回true。如果isRefreshScoped⽅法返回的false就判断当前Bean是否有@ConfigurationProperties注解如果有会被包装成
ConfigurationPropertiesBean存⼊当前的beans集合中(当有refresh发⽣时会重新绑定这些bean)。接下来继续进⼊到上⾯的ConfigurationPropertiesRebinder#rebind⽅法中。rebind⽅法中会对所有带有@ConfigurationProperties注解的类进⾏刷新,rebind⽅法中会对bean进⾏销毁和初始化。
AutowireCapableBeanFactory().destroyBean(bean);
AutowireCapableBeanFactory().initializeBean(bean, name);
4 RefreshScope刷新处理
当刷新refresh被调⽤后会执⾏RefreshScope#refreshAll⽅法
public class ContextRefresher {
public synchronized Set<String> refresh() {
Set<String> keys = refreshEnvironment();
freshAll();
return keys;
springboot aop}
}
RefreshScope#refreshAll⽅法
public void refreshAll() {
// 调⽤RefreshScope⽗类的destroy⽅法
super.destroy();
// 发布RefreshScopeRefreshedEvent事件,我们可以写个监听程序监听该事件
}
⽗类GenriceScope#destroy⽅法
public class GenericScope implements Scope, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, DisposableBean {
@Override
public void destroy() {
List<Throwable> errors = new ArrayList<Throwable>();
Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
for (BeanLifecycleWrapper wrapper : wrappers) {
try {
Lock lock = (Name()).writeLock();
lock.lock();
try {
wrapper.destroy();
} finally {
lock.unlock();
}
} catch (RuntimeException e) {
errors.add(e);
}
}
if (!errors.isEmpty()) {
throw (0));
}
}
}
wrapper#destroy⽅法
private static class BeanLifecycleWrapper {
private final String name;
private final ObjectFactory<?> objectFactory;
private Object bean;
private Runnable callback;
BeanLifecycleWrapper(String name, ObjectFactory<?> objectFactory) {
this.name = name;
this.objectFactory = objectFactory;
}
public Object getBean() {
if (this.bean == null) {
synchronized (this.name) {
if (this.bean == null) {
this.bean = Object();
}
}
}
return this.bean;
}
// 该⽅法就是清空上次创建的对象信息
public void destroy() {
if (this.callback == null) {
return;
}
synchronized (this.name) {
Runnable callback = this.callback;
callback.run();
}
this.callback = null;
this.bean = null;
}
}
}
当前清空了缓存对象后,下次再进⼊注⼊的时候会再次调⽤ObjectFacotry#getObject⽅法创建新的对象。
总结:当触发了refresh后,所有的带有@ConfigurationProperties注解的Bean都会⾃动的刷新并不需要@RefreshScope注解。⽽有@RefreshScope注解的⼀般在应⽤在⾮配置类上,有成员属性使⽤@Value注解的,如下:
@RestController
@RequestMapping("/refreshBeanProp")
@RefreshScope
public class RefreshScopeBeanPropController {
@Value("${custom}")
private String custom ;
@GetMapping("/get")
public String get() {
return custom ;
}
}
在此种情况下,调⽤/actuator/refresh 可使custom动态刷新,在ContextRefresher#refresh中将缓存的Bean清空了后重新⽣成Bean。
完毕!!!
给个关注+转发呗谢谢
众:Springboot实战案例锦集
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论