本文主要是介绍SpringCloud中动态配置刷新@RefreshScope的源码解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
@RefreshScope
public class App {
}@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
// 作用域为刷新作用域
@Scope("refresh")
@Documented
public @interface RefreshScope注解 {/*** 作用域代理的模式,默认为CGLIB*/@AliasFor(annotation = Scope.class)ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}// 导入刷新配置的核心处理类
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(ConfigurationPropertiesBindingPostProcessor.class)
public class ConfigurationPropertiesRebinderAutoConfiguration implements ApplicationContextAware, SmartInitializingSingleton {// Spring上下文private ApplicationContext context;// 创建ConfigurationPropertiesBeans的Bean,它保存了所有标注在当前上下文中所有的ConfigurationProperties类@Bean@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)public static ConfigurationPropertiesBeans configurationPropertiesBeans() {return new ConfigurationPropertiesBeans();}// 注入将指定ConfigurationProperties类进行重新绑定@Bean@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)public ConfigurationPropertiesRebinder configurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {ConfigurationPropertiesRebinder rebinder = new ConfigurationPropertiesRebinder(beans);return rebinder;}// 所有的Bena都初始化完成@Overridepublic void afterSingletonsInstantiated() {// 如果存在父容器if (this.context.getParent() != null) {// 获取ConfigurationPropertiesRebinder该BeanConfigurationPropertiesRebinder rebinder = this.context.getBean(ConfigurationPropertiesRebinder.class);// 获取父容器中所有的Bean进行重新加载for (String name : this.context.getParent().getBeanDefinitionNames()) {rebinder.rebind(name);}}}}@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RefreshScope.class)
@ConditionalOnProperty(name = RefreshAutoConfiguration.REFRESH_SCOPE_ENABLED, matchIfMissing = true)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@EnableConfigurationProperties(RefreshAutoConfiguration.RefreshProperties.class)
public class RefreshAutoConfiguration {// 注册刷新作用域@Bean@ConditionalOnMissingBean(RefreshScope.class)public static RefreshScope refreshScope() {return new RefreshScope();}// 配置数据上下文的刷新器,它负责刷新该作用域下的所有bean@Bean@ConditionalOnMissingBean@ConditionalOnBootstrapDisabledpublic ConfigDataContextRefresher configDataContextRefresher(ConfigurableApplicationContext context, RefreshScope scope, RefreshProperties properties) {return new ConfigDataContextRefresher(context, scope, properties);}/*** {@link com.alibaba.cloud.nacos.refresh.NacosContextRefresher#registerNacosListener(java.lang.String, java.lang.String)}* 配置刷新的监听器,该RefreshEvent是由对应的配置中心发布的事件,例如Nacos发生匹配变化的时候,就会触发一个RefreshEvent事件*/@Beanpublic RefreshEventListener refreshEventListener(ContextRefresher contextRefresher) {return new RefreshEventListener(contextRefresher);}
}// 配置数据上下文的刷新器,它负责刷新该作用域下的所有bean
public class ConfigDataContextRefresher extends ContextRefresher implements ApplicationListener<ContextRefreshedWithApplicationEvent> {// Spring上下文对象private ConfigurableApplicationContext context;// 刷新作用域的实现private RefreshScope scope;// SpringBoot的配置为了private SpringApplication application;@Overridepublic void onApplicationEvent(ContextRefreshedWithApplicationEvent event) {application = event.getSpringApplication();}// 更新环境对象,返回一个新的环境对象@Overrideprotected void updateEnvironment() {// 拷贝一份上下文环境存在的属性对象StandardEnvironment environment = copyEnvironment(getContext().getEnvironment());ConfigurableBootstrapContext bootstrapContext = getContext().getBeanProvider(ConfigurableBootstrapContext.class).getIfAvailable(DefaultBootstrapContext::new);// 加载所有的EnvironmentPostProcessor后置处理器List<String> classNames = SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, getClass().getClassLoader());Instantiator<EnvironmentPostProcessor> instantiator = new Instantiator<>(EnvironmentPostProcessor.class,(parameters) -> {parameters.add(DeferredLogFactory.class, logFactory);parameters.add(Log.class, logFactory::getLog);parameters.add(ConfigurableBootstrapContext.class, bootstrapContext);parameters.add(BootstrapContext.class, bootstrapContext);parameters.add(BootstrapRegistry.class, bootstrapContext);});// 实例化所有EnvironmentPostProcessor的类List<EnvironmentPostProcessor> postProcessors = instantiator.instantiate(classNames);for (EnvironmentPostProcessor postProcessor : postProcessors) {// 对拷贝的环境对象进行后置处理操作postProcessor.postProcessEnvironment(environment, application);}// 如果包含refreshArgs属性,将该属性移除if (environment.getPropertySources().contains(REFRESH_ARGS_PROPERTY_SOURCE)) {environment.getPropertySources().remove(REFRESH_ARGS_PROPERTY_SOURCE);}// 获取环境对象中的所有属性MutablePropertySources target = getContext().getEnvironment().getPropertySources();String targetName = null;// 保持属性的顺序for (PropertySource<?> source : environment.getPropertySources()) {String name = source.getName();if (target.contains(name)) {targetName = name;}if (!this.standardSources.contains(name)) {if (target.contains(name)) {target.replace(name, source);} else {if (targetName != null) {target.addAfter(targetName, source);targetName = name;} else {target.addFirst(source);targetName = name;}}}}}// 刷新配置以及对应的配置为了public synchronized Set<String> refresh() {// 刷新环境对象Set<String> keys = this.refreshEnvironment();// 刷新标注了@RefreshScope的类this.scope.refreshAll();return keys;}// 刷新环境对象,返回发生变化的属性public synchronized Set<String> refreshEnvironment() {Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());// 更新环境对象,返回一个新的环境对象this.updateEnvironment();// 获取发生变化的属性名Set<String> keys = this.changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();/**发布一个事件,该事件会由{@link ConfigurationPropertiesRebinder#onApplicationEvent(EnvironmentChangeEvent)}处理,从而刷新标注了**/this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));// 返回发生变化的属性return keys;}// 将原始的属性与当前的属性做对比,提取出发生变化的属性private Map<String, Object> changes(Map<String, Object> before, Map<String, Object> after) {Map<String, Object> result = new HashMap<>();for (String key : before.keySet()) {if (!after.containsKey(key)) {result.put(key, null);} else if (!equal(before.get(key), after.get(key))) {result.put(key, after.get(key));}}for (String key : after.keySet()) {if (!before.containsKey(key)) {result.put(key, after.get(key));}}return result;}
}@ManagedResource
public class RefreshScope extends GenericScope implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, Ordered {// 刷新当前作用域的所有Beanpublic void refreshAll() {/*** 创建该作用域Bean的流程{@link RefreshScope#get(String, ObjectFactory)}*/// 销毁所有refresh作用域的@Bean,下次需要发现该作用域没有缓存该Bean,则又会触发Bean的创建super.destroy();// 发布作用域刷新事件,这个事件我们自己可以监听的做一些事情this.context.publishEvent(new RefreshScopeRefreshedEvent());}/*** <pre>* 获取Bean对象,如果Bean对象不存在,则创建Bean* // 根据不同的作用域来创建对象* if (mbd.isSingleton()) {* // 从单例池中获取,不存在则创建* sharedInstance = getSingleton(beanName, () -> {* return createBean(beanName, mbd, args);* });* beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);* }* else if (mbd.isPrototype()) {* // 直接创建* prototypeInstance = createBean(beanName, mbd, args);* beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);* }* // 其他作用域* else {* // 获取自定义作用域的Scope对象* String scopeName = mbd.getScope();* Scope scope = this.scopes.get(scopeName);* // 调用Scope的get方法,从该作用域中获取Bean对象,如果不存在则创建对象* {@link BeanLifecycleWrapper#get(String, ObjectFactory)}* Object scopedInstance = scope.get(beanName, () -> {* return createBean(beanName, mbd, args);* });* beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);* }* </pre>*/// 自定义作用域的get方法,从指定位置返回该作用域的Bean对象,这个Bean对象由自己管理@Overridepublic Object get(String name, ObjectFactory<?> objectFactory) {// 缓存当前BeanBeanLifecycleWrapper value = this.cache.put(name, new BeanLifecycleWrapper(name, objectFactory));// 加读写锁this.locks.putIfAbsent(name, new ReentrantReadWriteLock());try {return value.getBean();} catch (RuntimeException e) {this.errors.put(name, e);throw e;}}
}// Bean的Scope生命周期包装类
public class BeanLifecycleWrapper {// BeanNameprivate final String name;// 创建Bean的工厂private final ObjectFactory<?> objectFactory;// Bean对象private volatile Object bean;// 销毁Bean执行的任务/*** 在创建的Bean的时候,如果Bean是DisposableBean类型,会自动注册一个任务,就是将该Bean执行所有的DestructionAwareBeanPostProcessor,处理一些销毁逻辑* {@link AbstractBeanFactory#registerDisposableBeanIfNecessary(String, Object, RootBeanDefinition)}*/private Runnable callback;BeanLifecycleWrapper(String name, ObjectFactory<?> objectFactory) {this.name = name;this.objectFactory = objectFactory;}public String getName() {return this.name;}public void setDestroyCallback(Runnable callback) {this.callback = callback;}// 获取Bean对象public Object getBean() {// 是否存在Bean对象if (this.bean == null) {synchronized (this.name) {// 使用对象工厂创建Bean对象if (this.bean == null) {// 保存Bean对象this.bean = this.objectFactory.getObject();}}}return this.bean;}// 销毁Bean对象public void destroy() {// 如果没有设置销毁时需要执行的任务,则不处理任何东西if (this.callback == null) {return;}synchronized (this.name) {// 执行指定的销毁任务Runnable callback = this.callback;if (callback != null) {callback.run();}// 清空当前Bean对象this.callback = null;this.bean = null;}}
}public class GenericScope implements Scope, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, DisposableBean {// 所有继承该类的作用域保存对应Bean的缓存对象private BeanLifecycleWrapperCache cache = new BeanLifecycleWrapperCache(new StandardScopeCache());// 销毁对象@Overridepublic void destroy() {// 清空所有该作用域的缓存BeanCollection<BeanLifecycleWrapper> wrappers = this.cache.clear();// 遍历所有该作用域的Bean的包装对象for (BeanLifecycleWrapper wrapper : wrappers) {// 调用每一个Bean包装器的销毁方法wrapper.destroy();}}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;// 注册当前作用域为refreshbeanFactory.registerScope(this.name, this);}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 获取所有的Beanfor (String name : registry.getBeanDefinitionNames()) {BeanDefinition definition = registry.getBeanDefinition(name);if (definition instanceof RootBeanDefinition root) {// 如果是作用域代理的Beanif (root.getDecoratedDefinition() != null && root.hasBeanClass() && root.getBeanClass() == ScopedProxyFactoryBean.class) {// 并且当前Bean的作用域正好是refreshif (getName().equals(root.getDecoratedDefinition().getBeanDefinition().getScope())) {// 修改当前Bean的BeanClass,增强一下,从ScopedProxyFactoryBean变成LockedScopedProxyFactoryBean// 它是继承ScopedProxyFactoryBean,就是在执行的过程中添加了读写锁root.setBeanClass(LockedScopedProxyFactoryBean.class);// 添加构造参数root.getConstructorArgumentValues().addGenericArgumentValue(this);root.setSynthetic(true);}}}}}
}/*** {@link com.alibaba.cloud.nacos.refresh.NacosContextRefresher#registerNacosListener(java.lang.String, java.lang.String)}* 配置刷新的监听器,该RefreshEvent是由对应的配置中心发布的事件,例如Nacos发生匹配变化的时候,就会触发一个RefreshEvent事件*/
public class RefreshEventListener implements SmartApplicationListener {// 配置数据上下文的刷新器private ConfigDataContextRefresher refresh;// 配置是否就绪private AtomicBoolean ready = new AtomicBoolean(false);public RefreshEventListener(ContextRefresher refresh) {this.refresh = refresh;}@Overridepublic boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {return ApplicationReadyEvent.class.isAssignableFrom(eventType) || RefreshEvent.class.isAssignableFrom(eventType);}@Overridepublic void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationReadyEvent) {// 标记已就绪this.ready.compareAndSet(false, true);}if (event instanceof RefreshEvent) {// 已就绪才会处理if (this.ready.get()) {// 使用配置数据的上下文对象进行刷新Set<String> keys = this.refresh.refresh();}}}
}@Component
public class ConfigurationPropertiesBeans implements BeanPostProcessor, ApplicationContextAware {// 标注了ConfigurationProperties的Bean对象private Map<String, ConfigurationPropertiesBean> beans = new HashMap<>();// Spring上下文private ApplicationContext applicationContext;// Bean工厂private ConfigurableListableBeanFactory beanFactory;// 刷新作用域private String refreshScope;// 刷新作用域是否初始化了private boolean refreshScopeInitialized;// 父容器中的ConfigurationPropertiesBeansprivate ConfigurationPropertiesBeans parent;// 初始化当前上下文中父容器的配置类ConfigurationProperties的Bean对象@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;if (applicationContext.getAutowireCapableBeanFactory() instanceof ConfigurableListableBeanFactory) {this.beanFactory = (ConfigurableListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();}AutowireCapableBeanFactory bf = applicationContext.getParent().getAutowireCapableBeanFactory();// 如果存在父容器if (applicationContext.getParent() != null && bf instanceof ConfigurableListableBeanFactory listable) {// 从父容器中获取获取ConfigurationPropertiesBeansString[] names = listable.getBeanNamesForType(ConfigurationPropertiesBeans.class);// 如果只存在一个if (names.length == 1) {// 将该父容器中的ConfigurationPropertiesBeans保存this.parent = (ConfigurationPropertiesBeans) listable.getBean(names[0]);// 将父容器中的ConfigurationProperties的Bean对象保存this.beans.putAll(this.parent.beans);}}}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 判断容器中的bean是不是refresh作用域// 如果是,不处理if (this.isRefreshScoped(beanName)) {return bean;}// 如果不是refresh作用域,获取执行beanName的Bean对象,标注了ConfigurationProperties才会返回对象// 如果不存在ConfigurationProperties注解,返回nullConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName);// 如果是属性配置Beanif (propertiesBean != null) {// 保存当前配置Bean信息this.beans.put(beanName, propertiesBean);}return bean;}// 判断容器中的bean是不是refresh作用域private boolean isRefreshScoped(String beanName) {// 如果刷新作用域为空(默认)并且没有被初始化过if (this.refreshScope == null && !this.refreshScopeInitialized) {// 开始初始化,标记初始化this.refreshScopeInitialized = true;// 遍历当前容器中的保存的所有作用域(例如,单例,原型,会话等等for (String scope : this.beanFactory.getRegisteredScopeNames()) {// 从容器中获取RefreshScope的Bean对象,如果当前作用域是RefreshScope,则保存该作用域if (this.beanFactory.getRegisteredScope(scope) instanceof org.springframework.cloud.context.scope.refresh.RefreshScope) {this.refreshScope = scope;break;}}}// 如果beanName为空或者没找到RefreshScope的Bean,表示不是RefreshScopeif (beanName == null || this.refreshScope == null) {return false;}// 如果当前Bean工厂包含指定的Bean,并且该Bean的作用域正是refresh(该Bean标注了@RefreshScope),返回truereturn this.beanFactory.containsBeanDefinition(beanName) && this.refreshScope.equals(this.beanFactory.getBeanDefinition(beanName).getScope());}// 获取所有标注了ConfigurationProperties的Bean对象的BeanNamepublic Set<String> getBeanNames() {return new HashSet<>(this.beans.keySet());}}// 配置属性Bean的重新绑定器
@Component
@ManagedResource
public class ConfigurationPropertiesRebinder implements ApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {// 需要重新绑定的配置类private ConfigurationPropertiesBeans beans;// Spring上下文对象private ApplicationContext applicationContext;// 重新绑定过程中的异常private Map<String, Exception> errors = new ConcurrentHashMap<>();// 需要将哪些配置Bean进行重新绑定public ConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {this.beans = beans;}// 重新绑定所有配置类@ManagedOperationpublic void rebind() {// 清空所有的异常信息this.errors.clear();// 遍历当前需要重新绑定的配置类Bean名称for (String name : this.beans.getBeanNames()) {// 重新绑定this.rebind(name);}}// 重新绑定指定配置类@ManagedOperationpublic boolean rebind(String name) {// 如果当前名称不在需要重新绑定的名单中,不处理if (!this.beans.getBeanNames().contains(name)) {return false;}ApplicationContext appContext = this.applicationContext;// 遍历所有层级的Spring上下文while (appContext != null) {// 如果包含该配置Bean,进行重新绑定if (appContext.containsLocalBean(name)) {return rebind(name, appContext);}// 如果当前容器不包含当前配置Bean,则查找父容器else {appContext = appContext.getParent();}}return false;}// 根据指定类型绑定public boolean rebind(Class type) {// 获取指定类型的配置BeanString[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext, type);if (beanNamesForType.length > 0) {// 获取到该Bean最原始的BeanName,因为该Bean可能设置了作用域代理String name = beanNamesForType[0];// 如果是作用域代理的Beanif (ScopedProxyUtils.isScopedTarget(name)) {// 获取最原始的bean名称,因为作用域代理的beanName经过加工name = ScopedProxyUtils.getOriginalBeanName(name);}// 开始绑定return rebind(name, this.applicationContext);}return false;}// 真正的开始查询绑定private boolean rebind(String name, ApplicationContext appContext) {try {// 获取需要绑定的BeanObject bean = appContext.getBean(name);// 获取到原始对象if (AopUtils.isAopProxy(bean)) {bean = ProxyUtils.getTargetObject(bean);}if (bean != null) {// 如果设置了不支持刷新,不处理if (getNeverRefreshable().contains(bean.getClass().getName())) {return false;}// 销毁该BeanappContext.getAutowireCapableBeanFactory().destroyBean(bean);// 重新初始化该BeanappContext.getAutowireCapableBeanFactory().initializeBean(bean, name);return true;}} catch (RuntimeException e) {// 保存绑定的异常信息this.errors.put(name, e);throw e;} catch (Exception e) {this.errors.put(name, e);throw new IllegalStateException("Cannot rebind to " + name, e);}return false;}// 不支持刷新@ManagedAttributepublic Set<String> getNeverRefreshable() {String neverRefresh = this.applicationContext.getEnvironment().getProperty("spring.cloud.refresh.never-refreshable", "com.zaxxer.hikari.HikariDataSource");return StringUtils.commaDelimitedListToSet(neverRefresh);}@ManagedAttributepublic Set<String> getBeanNames() {return new HashSet<>(this.beans.getBeanNames());}// 如何监听到环境对象发生了改变,需要重新绑定@Overridepublic void onApplicationEvent(EnvironmentChangeEvent event) {// 在配置属性发生改变的时候,会发布这个事件/*** {@link ConfigDataContextRefresher#refreshEnvironment}*/if (this.applicationContext.equals(event.getSource()) || event.getKeys().equals(event.getSource())) {this.rebind();}}}
这篇关于SpringCloud中动态配置刷新@RefreshScope的源码解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!