spring cloud 配置动态刷新

fxz大约 23 分钟

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创建代理时设置的TargetSourceSimpleBeanTargetSource

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();
       }
    }

}