配置中心动态刷新原理
前言
很容易想到想要实现动态刷新,至少需要做到以下两点
- 刷新属性配置,即
Environment
实例中的PropertySource
。 - 刷新对应的bean,以及依赖当前刷新bean的其它bean。
第一点看着还好,第二点难道要重新实例化要刷新的bean a,然后再找到相关其他的bean,把这个重新实例化的bean a注入进去吗?
刷新属性配置
SpringCloud刷新配置和Bean的入口为ContextRefresher
,然后自动配置类为RefreshAutoConfiguration
。
ContextRefresher
一个是抽象类,目前有两个实例
- LegacyContextRefresher,以前老的方式,如果应用开启了bootstrap上下文,则使用这个
- ConfigDataContextRefresher,在Spring Boot 2.4.0以后版本,可以使用spring.config.import导入外部配置,可以不再需要bootstrap上下文
ContextRefresher.java
/**
* 入口方法,刷新环境以及bean
*/
public synchronized Set<String> refresh() {
// 刷新环境
Set<String> keys = refreshEnvironment();
// 刷新bean
this.scope.refreshAll();
return keys;
}
public synchronized Set<String> refreshEnvironment() {
// 之前的属性配置
Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());
// 更新属性配置到环境中, 子类实现
updateEnvironment();
// 变化的key
Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
return keys;
}
LegacyContextRefresher.java
@Override
protected void updateEnvironment() {
addConfigFilesToEnvironment();
}
ConfigurableApplicationContext addConfigFilesToEnvironment() {
ConfigurableApplicationContext capture = null;
try {
StandardEnvironment environment = copyEnvironment(getContext().getEnvironment());
Map<String, Object> map = new HashMap<>();
map.put("spring.jmx.enabled", false);
map.put("spring.main.sources", "");
// gh-678 without this apps with this property set to REACTIVE or SERVLET fail
map.put("spring.main.web-application-type", "NONE");
map.put(BOOTSTRAP_ENABLED_PROPERTY, Boolean.TRUE.toString());
environment.getPropertySources().addFirst(new MapPropertySource(REFRESH_ARGS_PROPERTY_SOURCE, map));
SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class).bannerMode(Banner.Mode.OFF)
.web(WebApplicationType.NONE).environment(environment);
// Just the listeners that affect the environment (e.g. excluding logging
// listener because it has side effects)
// 只设置2个开启bootstrap上下文的和加载配置文件的Listener
builder.application().setListeners(
Arrays.asList(new BootstrapApplicationListener(), new BootstrapConfigFileApplicationListener()));
capture = builder.run();
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;
}
}
}
}
}
finally {
ConfigurableApplicationContext closeable = capture;
while (closeable != null) {
try {
closeable.close();
}
catch (Exception e) {
// Ignore;
}
if (closeable.getParent() instanceof ConfigurableApplicationContext) {
closeable = (ConfigurableApplicationContext) closeable.getParent();
}
else {
break;
}
}
}
return capture;
}
因为应用有开启bootstrap上下文,加载配置中心的配置依赖bootstrap上下文,因此使用SpringApplication
重新走了一遍Spring Boot的启动流程,重新初始化了Environment
实例,然后把PropertySource
应用到原来的Environment
实例中。
ConfigDataContextRefresher.java
@Override
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();
// 加载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);
});
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;
}
}
}
}
}
与老的相比,因为不再需要使用bootstrap上下文,因此只需要走一遍EnvironmentPostProcessor
逻辑即可,便能加载所有的配置信息了。
总结:可以看到spring cloud是将PropertySource
完整替换掉,而不是只是其中变动的配置项
刷新bean
Spring Cloud只会对被@RefreshScope
和@ConfigurationProperties
标注的bean进行刷新。
主要原理:对于被@RefreshScope
标注的bean,其实在容器中会注册两个BeanDefinition
,一个是代理对象,一个是目标对象,代理对象在调用方法时,会先调用容器的getBean方法拿到目标对象,然后用这个目标对象调用方法。因此只需要在刷新后让容器中的目标对象失效,然后重新创建便能达到动态刷新效果,而且还不用管那些注入过这个bean的其他bean,因为注入的是代理对象,而代理对象引用并没有发生任何变化。
区别:
- 代理:单例,可以被注入,beanName为定义的beanName,父类为目标类
- 目标类,scope=refresh,不可以被注入,beanName会带一个scopedTarget.前缀
先通过以下例子来看下刷新前后bean实例的变化。
@Component
@RefreshScope
public class ScopeBean {
}
@Getter
@Component
public class AutowireScopeBean {
@Autowired
private ScopeBean scopeBean;
}
测试类
@SpringBootTest
public class ApplicationTests {
@Autowired
private ConfigurableApplicationContext ac;
@Autowired
private ContextRefresher contextRefresher;
@Autowired
private AutowireScopeBean autowireScopeBean;
@Test
public void contextLoad() {
String[] beanNames = ac.getBeanNamesForType(ScopeBean.class);
// 目标对象beanName
Assertions.assertEquals("scopedTarget.scopeBean", beanNames[0]);
// 代理对象beanName
Assertions.assertEquals("scopeBean", beanNames[1]);
// 代理bean
ScopeBean beanBefore = ac.getBean(ScopeBean.class);
System.out.println(beanBefore.getClass());
System.out.println(beanBefore.getClass().getSuperclass());
// 目标bean
ScopeBean targetBeanBefore1 = (ScopeBean) ac.getBean("scopedTarget.scopeBean");
ScopeBean targetBeanBefore2 = (ScopeBean) ac.getBean("scopedTarget.scopeBean");
// 未刷新之前, 获取的目标对象为同一个
Assertions.assertSame(targetBeanBefore1, targetBeanBefore2);
// 刷新
contextRefresher.refresh();
ScopeBean beanAfter = ac.getBean(ScopeBean.class);
// 刷新后, 代理对象引用不会发生变化, 为同一个对象
Assertions.assertSame(beanBefore, beanAfter);
Assertions.assertSame(beanBefore, autowireScopeBean.getScopeBean());
ScopeBean targetBeanAfter = (ScopeBean) ac.getBean("scopedTarget.scopeBean");
// 刷新后,目标对象和刷新前为不同的对象
Assertions.assertNotSame(targetBeanBefore1, targetBeanAfter);
}
}
代码分析
动态刷新借助了Spring中的scope概念来实现的,最熟悉的应该便是singleton、prototype吧,默认情况下注册的bean都是singleton的,这些单例bean都被放在DefaultListableBeanFactory
中的singletonObjects
(实际是DefaultSingletonBeanRegistry
,继承的)属性中,也就是一个Map。
前置知识
容器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方法获取的。
@Scope.java
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.java
/**
* 定义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.java
@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.java
/**
* 刷新, ContextRefresher.refresh方法会调用
*/
public void refreshAll() {
super.destroy();
this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
GenericScope.java
@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不像@RefreshScope
标注的一样,它只是在环境发生变化时,重新绑定下属性,并不会重新创建新的对象示例,也没有代理对象。
ContextRefresher.java
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;
}
ConfigurationPropertiesRebinder.java
/**
* 监听EnvironmentChangeEvent事件
*/
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
if (this.applicationContext.equals(event.getSource())
|| event.getKeys().equals(event.getSource())) {
// 重新绑定属性
rebind();
}
}
public void rebind() {
this.errors.clear();
// 只包含被@ConfigurationProperties标注的类, 并且没有被@RefreshScope标记
for (String name : this.beans.getBeanNames()) {
rebind(name);
}
}
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;
}
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;
}