spring cloud 配置动态刷新
spring cloud 配置动态刷新
省流
@RefreshScope是一个scope。会创建代理对象和被代理对象两个bean。刷新是清空掉被代理对象,下一次重新调用getBean走一遍逻辑借口。触发的时机是客户端接收到刷新事件,此时会刷新环境,然后刷新scope。
@ConfigurationProperties的原理是通过后置处理器记录下加了@ConfigurationProperties的bean,然后通过监听环境刷新事件,销毁bean然后再初始化bean实现刷新配置属性。
// 销毁bean, 释放资源, 比如close等方法, 不会从容器中移除
appContext.getAutowireCapableBeanFactory().destroyBean(bean);
// 重新初始化, 注意@ConfigurationProperties逻辑是在
// BeanPostProcessor.postProcessBeforeInitialization执行的, initializeBean包含了这一步
appContext.getAutowireCapableBeanFactory().initializeBean(bean, name);
@RefreshScope
- 刷新环境,创建一个新的environment,然后走一遍EnvironmentPostProcessor的到最新的配置。
- 清空refreshScope bean,下一次getBean的时候,走的是scope中get的逻辑,会创建新的bean(这里其实清空的是被代理的对象,被注入的是代理ben)。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RefreshScope.class)
@ConditionalOnProperty(name = RefreshAutoConfiguration.REFRESH_SCOPE_ENABLED, matchIfMissing = true)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@EnableConfigurationProperties(RefreshAutoConfiguration.RefreshProperties.class)
public class RefreshAutoConfiguration {
/**
* Name of the refresh scope name.
*/
public static final String REFRESH_SCOPE_NAME = "refresh";
/**
* Name of the prefix for refresh scope.
*/
public static final String REFRESH_SCOPE_PREFIX = "spring.cloud.refresh";
/**
* Name of the enabled prefix for refresh scope.
*/
public static final String REFRESH_SCOPE_ENABLED = REFRESH_SCOPE_PREFIX + ".enabled";
// 创建、销毁RefreshScope作用域的bean。
@Bean
@ConditionalOnMissingBean(RefreshScope.class)
public static RefreshScope refreshScope() {
return new RefreshScope();
}
// sb2.4以后有新的加载配置的方式,不再使用bootstrap的方式,此为旧的刷新配置数据的方式。
@Bean
@ConditionalOnMissingBean
@ConditionalOnBootstrapEnabled
public LegacyContextRefresher legacyContextRefresher(ConfigurableApplicationContext context, RefreshScope scope,
RefreshProperties properties) {
return new LegacyContextRefresher(context, scope, properties);
}
// 支持sb2.4以后新的配置加载方式,实现环境配置数据的刷新。
@Bean
@ConditionalOnMissingBean
@ConditionalOnBootstrapDisabled
public ConfigDataContextRefresher configDataContextRefresher(ConfigurableApplicationContext context,
RefreshScope scope, RefreshProperties properties) {
return new ConfigDataContextRefresher(context, scope, properties);
}
// 处理刷新事件,调用ContextRefresher。
@Bean
public RefreshEventListener refreshEventListener(ContextRefresher contextRefresher) {
return new RefreshEventListener(contextRefresher);
}
...........................
}
监听RefreshEvent
入口:RefreshEventListener#onApplicationEvent。
作用就是调用ContextRefresher刷新Environment同时清空refresh scope的bean。
public class RefreshEventListener implements SmartApplicationListener {
private static Log log = LogFactory.getLog(RefreshEventListener.class);
private ContextRefresher refresh;
private AtomicBoolean ready = new AtomicBoolean(false);
public RefreshEventListener(ContextRefresher refresh) {
this.refresh = refresh;
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationReadyEvent.class.isAssignableFrom(eventType)
|| RefreshEvent.class.isAssignableFrom(eventType);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationReadyEvent) {
handle((ApplicationReadyEvent) event);
}
else if (event instanceof RefreshEvent) {
handle((RefreshEvent) event);
}
}
public void handle(ApplicationReadyEvent event) {
this.ready.compareAndSet(false, true);
}
public void handle(RefreshEvent event) {
if (this.ready.get()) { // don't handle events before app is ready
log.debug("Event received " + event.getEventDesc());
Set<String> keys = this.refresh.refresh();
log.info("Refresh keys changed: " + keys);
}
}
}
可以看到RefreshEventListener响应RefreshEvent并调用ContextRefresher进行刷新。但是这个RefreshEvent是哪里来的?
在nacos配置中心客户端实现中NacosContextRefresher听过监听ApplicationReadyEvent来注册监听器。
NacosContextRefresher:
// 应用程序就绪后注册监听器
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// many Spring context
if (this.ready.compareAndSet(false, true)) {
this.registerNacosListenersForApplications();
}
}
// 注册配置监听器
private void registerNacosListenersForApplications() {
if (isRefreshEnabled()) {
for (NacosPropertySource propertySource : NacosPropertySourceRepository
.getAll()) {
if (!propertySource.isRefreshable()) {
continue;
}
String dataId = propertySource.getDataId();
registerNacosListener(propertySource.getGroup(), dataId);
}
}
}
private void registerNacosListener(final String groupKey, final String dataKey) {
String key = NacosPropertySourceRepository.getMapKey(dataKey, groupKey);
Listener listener = listenerMap.computeIfAbsent(key,
lst -> new AbstractSharedListener() {
@Override
public void innerReceive(String dataId, String group,
String configInfo) {
refreshCountIncrement();
nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo);
// 发布RefreshEvent事件
applicationContext.publishEvent(
new RefreshEvent(this, null, "Refresh Nacos config"));
if (log.isDebugEnabled()) {
log.debug(String.format(
"Refresh Nacos config group=%s,dataId=%s,configInfo=%s",
group, dataId, configInfo));
}
}
});
try {
configService.addListener(dataKey, groupKey, listener);
log.info("[Nacos Config] Listening config: dataId={}, group={}", dataKey,
groupKey);
}
catch (NacosException e) {
log.warn(String.format(
"register fail for nacos listener ,dataId=[%s],group=[%s]", dataKey,
groupKey), e);
}
}
监听器注册了,那监听器的逻辑在哪里触发的?
在ClientWorker的构造方法中会创建ConfigRpcTransportClient。
ClientWorker:
public ClientWorker(final ConfigFilterChainManager configFilterChainManager, ServerListManager serverListManager,
final Properties properties) throws NacosException {
this.configFilterChainManager = configFilterChainManager;
init(properties);
agent = new ConfigRpcTransportClient(properties, serverListManager);
int count = ThreadUtils.getSuitableThreadCount(THREAD_MULTIPLE);
ScheduledExecutorService executorService = Executors
.newScheduledThreadPool(Math.max(count, MIN_THREAD_NUM), r -> {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Worker");
t.setDaemon(true);
return t;
});
agent.setExecutor(executorService);
agent.start();
}
ConfigRpcTransportClient:
public void start() throws NacosException {
if (securityProxy.isEnabled()) {
securityProxy.login(serverListManager.getServerUrls());
this.executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
securityProxy.login(serverListManager.getServerUrls());
}
}, 0, this.securityInfoRefreshIntervalMills, TimeUnit.MILLISECONDS);
}
startInternal();
}
public void startInternal() throws NacosException {
executor.schedule(() -> {
while (!executor.isShutdown() && !executor.isTerminated()) {
try {
listenExecutebell.poll(5L, TimeUnit.SECONDS);
if (executor.isShutdown() || executor.isTerminated()) {
continue;
}
executeConfigListen();
} catch (Exception e) {
LOGGER.error("[ rpc listen execute ] [rpc listen] exception", e);
}
}
}, 0L, TimeUnit.MILLISECONDS);
}
可以看到startInternal方法里面有一个死循环,通过listenExecutebell阻塞对列做并发控制。会一直执行executeConfigListen方法。
而executeConfigListen方法会检查配置是否发生变更,最终调用前面注册的监听器,发布RefreshEvent事件。
ContextRefresher
- 刷新环境,创建一个新的environment,然后走一遍EnvironmentPostProcessor的到最新的配置。
- 清空refreshScope bean,下一次getBean的时候,走的是scope中get的逻辑,会创建新的bean(这里其实清空的是被代理的对象,被注入的是代理bean)。
ContextRefresher:
public synchronized Set<String> refresh() {
Set<String> keys = refreshEnvironment();
this.scope.refreshAll();
return keys;
}
public synchronized Set<String> refreshEnvironment() {
Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());
updateEnvironment();
Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
return keys;
}
protected abstract void updateEnvironment();
ConfigDataContextRefresher:
//刷新环境,创建一个新的environment,然后走一遍EnvironmentPostProcessor的到最新的配置。
protected void updateEnvironment() {
if (logger.isTraceEnabled()) {
logger.trace("Re-processing environment to add config data");
}
StandardEnvironment environment = copyEnvironment(getContext().getEnvironment());
ConfigurableBootstrapContext bootstrapContext = getContext().getBeanProvider(ConfigurableBootstrapContext.class)
.getIfAvailable(DefaultBootstrapContext::new);
// run thru all EnvironmentPostProcessor instances. This lets things like vcap and
// decrypt happen after refresh. The hard coded call to
// ConfigDataEnvironmentPostProcessor.applyTo() is now automated as well.
DeferredLogFactory logFactory = new PassthruDeferredLogFactory();
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);
});
List<EnvironmentPostProcessor> postProcessors = instantiator.instantiate(classNames);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(environment, application);
}
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);
// update targetName to preserve ordering
targetName = name;
}
else {
// targetName was null so we are at the start of the list
target.addFirst(source);
targetName = name;
}
}
}
}
}
RefreshScope:
// 清空refreshScope bean,下一次getBean的时候,走的是scope中get的逻辑,会创建新的bean(这里其实清空的是被代理的对象,被注入的是代理ben,也就是使用@清空RefreshScope标注的bean最终会注册两个bean)。
@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());
}
GenericScope:
@Override
public void destroy() {
List<Throwable> errors = new ArrayList<Throwable>();
Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
for (BeanLifecycleWrapper wrapper : wrappers) {
try {
Lock lock = this.locks.get(wrapper.getName()).writeLock();
lock.lock();
try {
wrapper.destroy();
}
finally {
lock.unlock();
}
}
catch (RuntimeException e) {
errors.add(e);
}
}
if (!errors.isEmpty()) {
throw wrapIfNecessary(errors.get(0));
}
this.errors.clear();
}
代理对象
容器getBean方法部分片段:
// Create bean instance.
// 单例对象
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 原型对象
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
// 通过对应Scope的get方法获取
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
可以看到,如果scope属性不是singleton、prototype,是从Scope对象的get方法获取的。
public @interface Scope {
/**
* scope名字
* 目前有prototype、singleton
* servlet web环境增加了request, session
* spring cloud增加了refresh, local
* 其它的值会报错,当然也可以自己扩展,增加对应的名字实现就能使用了
* 默认值为空字符串,相当于singleton
*/
String value() default "";
/**
* 同value
*/
@AliasFor("value")
String scopeName() default "";
/**
* 是否需要创建代理
* DEFAULT会跟随全局,基本相当于NO
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
@RefreshScope
/**
* 定义scopeName=refresh
* 并且使用cglib方式创建代理
*/
@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;
}
修改BeanDefinition
上文说到会注册两个bean到容器中,这个会根据proxyMode的属性来决定是否需要注册代理beanDefinition定义。
AnnotationConfigUtils.java(这只是一个其中入口,底层最终都会调用ScopedProxyCreator.createScopedProxy)
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
ScopedProxyCreator.java
final class ScopedProxyCreator {
private ScopedProxyCreator() {
}
public static BeanDefinitionHolder createScopedProxy(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}
public static String getTargetBeanName(String originalBeanName) {
return ScopedProxyUtils.getTargetBeanName(originalBeanName);
}
}
ScopedProxyUtils.java
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
String originalBeanName = definition.getBeanName();
BeanDefinition targetDefinition = definition.getBeanDefinition();
// 拼接scopedTarget.前缀
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
// 代理BeanDefinition
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
// 目标bean不能被注入
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
创建代理对象
代理BeanDefinition类是ScopedProxyFactoryBean
,这是一个FactoryBean
,它会基于ProxyFactory
创建一个代理。
ProxyFactory
是Spring创建代理的公共工厂,以cglib代理为例,它内部会调用CglibAopProxy
的getProxy方法拿到代理类,该类设置了一个公共拦截器DynamicAdvisedInterceptor
。
DynamicAdvisedInterceptor.java
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获取目标对象(关键点)
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = invokeMethod(target, method, argsToUse, methodProxy);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
}
/**
* CGLIB uses this to drive proxy creation.
*/
@Override
public int hashCode() {
return this.advised.hashCode();
}
}
而ScopedProxyFactoryBean
创建代理时设置的TargetSource
为SimpleBeanTargetSource
。
ScopedProxyFactoryBean.java
public class ScopedProxyFactoryBean extends ProxyConfig
implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {
/** The TargetSource that manages scoping. */
private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();
public void setBeanFactory(BeanFactory beanFactory) {
if (!(beanFactory instanceof ConfigurableBeanFactory)) {
throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
}
ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
this.scopedTargetSource.setBeanFactory(beanFactory);
ProxyFactory pf = new ProxyFactory();
pf.copyFrom(this);
// 设置代理的TargetSource
pf.setTargetSource(this.scopedTargetSource);
Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
Class<?> beanType = beanFactory.getType(this.targetBeanName);
if (beanType == null) {
throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
"': Target type could not be determined at the time of proxy creation.");
}
if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
}
// Add an introduction that implements only the methods on ScopedObject.
ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
// Add the AopInfrastructureBean marker to indicate that the scoped proxy
// itself is not subject to auto-proxying! Only its target bean is.
pf.addInterface(AopInfrastructureBean.class);
this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}
}
SimpleBeanTargetSource.java
public class SimpleBeanTargetSource extends AbstractBeanFactoryBasedTargetSource {
@Override
public Object getTarget() throws Exception {
return getBeanFactory().getBean(getTargetBeanName());
}
}
可以看到绕了这么一大圈,就是创建一个代理类,然后调用方法时会调用容器的getBean方法拿到目标对象再执行方法。
拿目标对象
目标对象的scope=refresh,因此需要对应的Scope提供get方法来获取
Scope.java(接口)
public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory);
@Nullable
Object remove(String name);
}
@RefreshScope
注解对应的Scope实现为RefreshScope
,而RefreshScope
又继承了GenericScope
。
GenericScope:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
// 往容器注册Scope,如果不注册,getBean方法会报错
beanFactory.registerScope(this.name, this);
setSerializationId(beanFactory);
}
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 注意这里,name存在,则返回原来的wrapper,相当于Map的putIfAbsent
// 因此如果不删除的话拿到的一直是同一个对象
BeanLifecycleWrapper 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;
}
}
RefreshScope:
/**
* 刷新, ContextRefresher.refresh方法会调用
*/
public void refreshAll() {
super.destroy();
this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
GenericScope:
@Override
public void destroy() {
List<Throwable> errors = new ArrayList<Throwable>();
// 清除缓存,下次容器中的getBean变化重新创建一个对象了
Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
for (BeanLifecycleWrapper wrapper : wrappers) {
try {
Lock lock = this.locks.get(wrapper.getName()).writeLock();
lock.lock();
try {
wrapper.destroy();
}
finally {
lock.unlock();
}
}
catch (RuntimeException e) {
errors.add(e);
}
}
if (!errors.isEmpty()) {
throw wrapIfNecessary(errors.get(0));
}
this.errors.clear();
}
@ConfigurationProperties
- 记录 @ConfigurationProperties 的bean。
- 在环境发生变化时,重新绑定下属性,并不会重新创建新的对象实例,也没有代理对象。
// 销毁bean, 释放资源, 比如close等方法, 不会从容器中移除 appContext.getAutowireCapableBeanFactory().destroyBean(bean); // 重新初始化, 注意@ConfigurationProperties逻辑是在 // BeanPostProcessor.postProcessBeforeInitialization执行的, initializeBean包含了这一步 appContext.getAutowireCapableBeanFactory().initializeBean(bean, name);
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(ConfigurationPropertiesBindingPostProcessor.class)
public class ConfigurationPropertiesRebinderAutoConfiguration
implements ApplicationContextAware, SmartInitializingSingleton {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.context = applicationContext;
}
// 收集加了@ConfigurationProperties的bean。
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public static ConfigurationPropertiesBeans configurationPropertiesBeans() {
return new ConfigurationPropertiesBeans();
}
// 销毁加了@ConfigurationProperties的bean,然后重新初始化(并没有在容器中删除原来的bean,也没有代理对象)。
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public ConfigurationPropertiesRebinder configurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {
ConfigurationPropertiesRebinder rebinder = new ConfigurationPropertiesRebinder(beans);
return rebinder;
}
@Override
public void afterSingletonsInstantiated() {
// After all beans are initialized explicitly rebind beans from the parent
// so that changes during the initialization of the current context are
// reflected. In particular this can be important when low level services like
// decryption are bootstrapped in the parent, but need to change their
// configuration before the child context is processed.
if (this.context.getParent() != null) {
// TODO: make this optional? (E.g. when creating child contexts that prefer to
// be isolated.)
ConfigurationPropertiesRebinder rebinder = this.context.getBean(ConfigurationPropertiesRebinder.class);
for (String name : this.context.getParent().getBeanDefinitionNames()) {
rebinder.rebind(name);
}
}
}
}
@Component
@ManagedResource
public class ConfigurationPropertiesRebinder
implements ApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {
private ConfigurationPropertiesBeans beans;
private ApplicationContext applicationContext;
..............
@ManagedOperation
public void rebind() {
this.errors.clear();
for (String name : this.beans.getBeanNames()) {
rebind(name);
}
}
@ManagedOperation
public boolean rebind(String name) {
if (!this.beans.getBeanNames().contains(name)) {
return false;
}
ApplicationContext appContext = this.applicationContext;
while (appContext != null) {
if (appContext.containsLocalBean(name)) {
return rebind(name, appContext);
}
else {
appContext = appContext.getParent();
}
}
return false;
}
public boolean rebind(Class type) {
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext, type);
if (beanNamesForType.length > 0) {
String name = beanNamesForType[0];
if (ScopedProxyUtils.isScopedTarget(name)) {
name = ScopedProxyUtils.getOriginalBeanName(name);
}
return rebind(name, this.applicationContext);
}
return false;
}
private boolean rebind(String name, ApplicationContext appContext) {
try {
Object bean = appContext.getBean(name);
if (AopUtils.isAopProxy(bean)) {
// 如果被代理了,拿到目标对象
bean = ProxyUtils.getTargetObject(bean);
}
if (bean != null) {
// TODO: determine a more general approach to fix this.
// see
// https://github.com/spring-cloud/spring-cloud-commons/issues/571
if (getNeverRefreshable().contains(bean.getClass().getName())) {
return false; // ignore
}
// 销毁bean, 释放资源, 比如close等方法, 不会从容器中移除
appContext.getAutowireCapableBeanFactory().destroyBean(bean);
// 重新初始化, 注意@ConfigurationProperties逻辑是在
// BeanPostProcessor.postProcessBeforeInitialization执行的, initializeBean包含了这一步
appContext.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;
}
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
if (this.applicationContext.equals(event.getSource())
// Backwards compatible
|| event.getKeys().equals(event.getSource())) {
rebind();
}
}
}