spring boot 自动刷新配置导致的出错

一、现象总结
运维人员只要一修改分布式配置,程序就报错,此时的健康检测也是出错。
但是,重启应用是能够成功的。
程序中有配置类使用注解@RefreshScope,用于实时更新,但又不想重启应用。

二、技术栈
分布式配置consul + spring boot 2.0 + mysql数据库连接池HicariCP

三、健康检测的错误详情

"status":"DOWN", "details":{ "diskSpace":{ "status":"UP", "details":{ "total":52710469632, "free":44208345088, "threshold":10485760 "db":{ "status":"UP", "details":{ "database":"MySQL", "hello":1 "elasticsearch":{ "status":"UP", "details":{ "clusterName":"es-cluster", "numberOfNodes":3, "numberOfDataNodes":3, "activePrimaryShards":94, "activeShards":193, "relocatingShards":0, "initializingShards":0, "unassignedShards":0 "refreshScope":{ "status":"DOWN", "details":{ "error":"org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'dataSource': Could not bind properties to 'HikariDataSource' : prefix=spring.datasource.hikari, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.datasource.hikari' to com.zaxxer.hikari.HikariDataSource" "discoveryComposite":{ "status":"UP", "details":{ "discoveryClient":{ "status":"UP", "details":{ "services":[ "user-service" "hystrix":{ "status":"UP" "redis":{ "status":"UP", "details":{ "version":"3.2.11"

四、java后端的日志打印出错详情

2021-03-04 10:51:01.651 ERROR 20017 --- [TaskScheduler-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task.
org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'dataSource': Could not bind properties to 'HikariDataSource' : prefix=spring.datasource.hikari, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.datasource.hikari' to com.zaxxer.hikari.HikariDataSource
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:109) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:93) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:423) ~[spring-beans-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1702) ~[spring-beans-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:414) ~[spring-beans-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.rebind(ConfigurationPropertiesRebinder.java:102) ~[spring-cloud-context-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.rebind(ConfigurationPropertiesRebinder.java:84) ~[spring-cloud-context-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.onApplicationEvent(ConfigurationPropertiesRebinder.java:141) ~[spring-cloud-context-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.onApplicationEvent(ConfigurationPropertiesRebinder.java:50) ~[spring-cloud-context-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:399) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:353) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.cloud.context.refresh.ContextRefresher.refresh(ContextRefresher.java:65) ~[spring-cloud-context-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.cloud.endpoint.event.RefreshEventListener.handle(RefreshEventListener.java:36) ~[spring-cloud-context-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:264) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:182) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:144) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:399) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:353) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at org.springframework.cloud.consul.config.ConfigWatch.watchConfigKeyValues(ConfigWatch.java:158) ~[spring-cloud-consul-config-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.0.4.RELEASE.jar!/:5.0.4.RELEASE]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_181]
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_181]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_181]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_181]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]
Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.datasource.hikari' to com.zaxxer.hikari.HikariDataSource
    at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:250) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:226) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:210) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:192) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bind(ConfigurationPropertiesBinder.java:78) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:106) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    ... 36 common frames omitted
Caused by: java.lang.IllegalStateException: Unable to set value for property pool-name
    at org.springframework.boot.context.properties.bind.JavaBeanBinder$BeanProperty.setValue(JavaBeanBinder.java:322) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:78) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:61) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:53) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder.lambda$null$5(Binder.java:339) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_181]
    at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359) ~[na:1.8.0_181]
    at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126) ~[na:1.8.0_181]
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498) ~[na:1.8.0_181]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485) ~[na:1.8.0_181]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_181]
    at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152) ~[na:1.8.0_181]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_181]
    at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464) ~[na:1.8.0_181]
    at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$6(Binder.java:340) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:439) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:425) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder$Context.access$400(Binder.java:379) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:337) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:279) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:221) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    ... 40 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
    at org.springframework.boot.context.properties.bind.JavaBeanBinder$BeanProperty.setValue(JavaBeanBinder.java:319) ~[spring-boot-2.0.0.RELEASE.jar!/:2.0.0.RELEASE]
    ... 60 common frames omitted
Caused by: java.lang.IllegalStateException: The configuration of the pool is sealed once started.  Use HikariConfigMXBean for runtime changes.
    at com.zaxxer.hikari.HikariConfig.setPoolName(HikariConfig.java:861) ~[HikariCP-2.7.8.jar!/:na]
    ... 65 common frames omitted

可以看出,主要的错误在于末尾!! 这也是仅从健康检测的错误提示,无法看到出错在哪的原因。

java.lang.IllegalStateException: The configuration of the pool is sealed once started.  Use HikariConfigMXBean for runtime changes.
    at com.zaxxer.hikari.HikariConfig.setPoolName(HikariConfig.java:861) ~[HikariCP-2.7.8.jar!/:na]

五、consul的主要配置

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://mysql2.xx.net:3306/xxx?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
    username: xxxx
    password: xxxx
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 10
      maximum-pool-size: 150
      auto-commit: true
      idle-timeout: 600000
      pool-name: DatebookHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000

六、出错的原因
1、com.zaxxer.hikari.HikariConfig.setPoolName

public void setPoolName(String poolName)
      checkIfSealed();
      this.poolName = poolName;
//这里引入了一个重要的vovatile变量
private volatile boolean sealed;
private void checkIfSealed()
      if (sealed) throw new IllegalStateException("The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.");
void seal()
      this.sealed = true;

在数据源初始化和连接建立的时候,调用seal()方法。
见类public class HikariConnectionProvider implements ConnectionProvider, Configurable, Stoppable

if (isClosed()) { throw new SQLException("HikariDataSource " + this + " has been closed."); // 如果fast连接池存在,则直接跳转至获取连接的方法内。 if (fastPathPool != null) { return fastPathPool.getConnection(); // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java HikariPool result = pool; if (result == null) { synchronized (this) { result = pool; if (result == null) { validate(); LOGGER.info("{} - Starting...", getPoolName()); try { pool = result = new HikariPool(this); this.seal(); catch (PoolInitializationException pie) { if (pie.getCause() instanceof SQLException) { throw (SQLException) pie.getCause(); else { throw pie; LOGGER.info("{} - Start completed.", getPoolName()); return result.getConnection();

PS: getConnection()里的实现,也比较简单,附上源码:
代码行数不错,先是采用Semaphore信号量的同步机制,实时触发关闭连接,循环判断是否超时,由PoolEntry去创建连接代理。同时收集指标信息。

public Connection getConnection(final long hardTimeout) throws SQLException
      suspendResumeLock.acquire();
      final long startTime = currentTime();
      try {
         long timeout = hardTimeout;
            PoolEntry poolEntry = connectionBag.borrow(timeout, MILLISECONDS);
            if (poolEntry == null) {
               break; // We timed out... break and throw exception
            final long now = currentTime();
            if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > aliveBypassWindowMs && !isConnectionAlive(poolEntry.connection))) {
               closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE);
               timeout = hardTimeout - elapsedMillis(startTime);
            else {
               metricsTracker.recordBorrowStats(poolEntry, startTime);
               return poolEntry.createProxyConnection(leakTaskFactory.schedule(poolEntry), now);
         } while (timeout > 0L);
         metricsTracker.recordBorrowTimeoutStats(startTime);
         throw createTimeoutException(startTime);
      catch (InterruptedException e) {
         Thread.currentThread().interrupt();
         throw new SQLException(poolName + " - Interrupted during connection acquisition", e);
      finally {
         suspendResumeLock.release();

2、配置自动加载
分析到这里,我们需要解释的是,为什么没有加@RefreshScope注解的数据库配置项会重新加载?
关于更多有关配置热更新的可以参考网址http://www.scienjus.com/spring-cloud-refresh/

文章开头说了,程序中并没有手写对于HikariCP的配置项,而是简单的使用@RefreshScope注解。

怀疑是spring boot autoconfigure 在加载数据源的时候,有指定刷新类DataSourceProperties。

"sourceType": "org.springframework.boot.autoconfigure.jdbc.DataSourceProperties", "name": "spring.datasource.type", "description": "Fully qualified name of the connection pool implementation to use. By default, it\n is auto-detected from the classpath.", "type": "java.lang.Class<? extends javax.sql.DataSource>"

检索spring.datasource.type,找到它的java配置类是DataSourceProperties。

@ConfigurationProperties(
    prefix = "spring.datasource"
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {

这里也没有直接写类DataSourceProperties的scope=refresh.

于是,断点跟踪spring-cloud-context-2.0.0.RELEASE.jar中的几个关键类:
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration

@Bean
    @ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
    public ConfigurationPropertiesBeans configurationPropertiesBeans() {
        // Since this is a BeanPostProcessor we have to be super careful not to
        // cause a cascade of bean instantiation. Knowing the *name* of the beans we
        // need is super optimal, but a little brittle (unfortunately we have no
        // choice).
        ConfigurationBeanFactoryMetadata metaData = this.context.getBean(
                ConfigurationBeanFactoryMetadata.BEAN_NAME,
                        ConfigurationBeanFactoryMetadata.class);
        ConfigurationPropertiesBeans beans = new ConfigurationPropertiesBeans();
        beans.setBeanMetaDataStore(metaData);
        return beans;
    @Bean
    @ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
    public ConfigurationPropertiesRebinder configurationPropertiesRebinder(
            ConfigurationPropertiesBeans beans) {
        ConfigurationPropertiesRebinder rebinder = new ConfigurationPropertiesRebinder(
                beans);
        return rebinder;

进一步看ConfigurationPropertiesBeans类的实现细节,

@Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
// 如果bean的scope不是refresh, 则返回。
// 而org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari的scope切实地等于refresh
        if (isRefreshScoped(beanName)) {
            return bean;
        ConfigurationProperties annotation = AnnotationUtils.findAnnotation(
                bean.getClass(), ConfigurationProperties.class);
        if (annotation != null) {
            this.beans.put(beanName, bean);
        else if (this.metaData != null) {
            annotation = this.metaData.findFactoryAnnotation(beanName,
                    ConfigurationProperties.class);
            if (annotation != null) {
                this.beans.put(beanName, bean);
        return bean;
    private boolean isRefreshScoped(String beanName) {
        if (this.refreshScope == null && !this.refreshScopeInitialized) {
            this.refreshScopeInitialized = true;
            for (String scope : this.beanFactory.getRegisteredScopeNames()) {
                if (this.beanFactory.getRegisteredScope(scope) instanceof org.springframework.cloud.context.scope.refresh.RefreshScope) {
                    this.refreshScope = scope;
                    break;
        if (beanName == null || this.refreshScope == null) {
            return false;
        return this.beanFactory.containsBeanDefinition(beanName)
                && this.refreshScope.equals(this.beanFactory.getBeanDefinition(beanName)
                        .getScope());

至于为什么org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari它的scope=refresh。可以看类org.springframework.cloud.autoconfigure.RefreshAutoConfiguration

@Component protected static class RefreshScopeBeanDefinitionEnhancer implements BeanDefinitionRegistryPostProcessor { * Class names for beans to post process into refresh scope. Useful when you don't * control the bean definition (e.g. it came from auto-configuration). private Set<String> refreshables = new HashSet<>( Arrays.asList("com.zaxxer.hikari.HikariDataSource")); private Environment environment; public Set<String> getRefreshable() { return this.refreshables; public void setRefreshable(Set<String> refreshables) { if (this.refreshables != refreshables) { this.refreshables.clear(); this.refreshables.addAll(refreshables); public void setExtraRefreshable(Set<String> refreshables) { this.refreshables.addAll(refreshables); @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { for (String name : registry.getBeanDefinitionNames()) { BeanDefinition definition = registry.getBeanDefinition(name); if (isApplicable(registry, name, definition)) { BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, name); BeanDefinitionHolder proxy = ScopedProxyUtils .createScopedProxy(holder, registry, true); definition.setScope("refresh"); registry.registerBeanDefinition(proxy.getBeanName(), proxy.getBeanDefinition()); private boolean isApplicable(BeanDefinitionRegistry registry, String name, BeanDefinition definition) { String scope = definition.getScope(); if ("refresh".equals(scope)) { // Already refresh scoped return false; String type = definition.getBeanClassName(); if (registry instanceof BeanFactory) { Class<?> cls = ((BeanFactory) registry).getType(name); if (cls != null) { type = cls.getName(); if (type != null) { if (this.environment == null && registry instanceof BeanFactory) { this.environment = ((BeanFactory) registry) .getBean(Environment.class); if (this.environment == null) { this.environment = new StandardEnvironment(); Binder.get(environment).bind("spring.cloud.refresh", Bindable.ofInstance(this)); return this.refreshables.contains(type); return false;