我读了这个Dynamic Configuration Properties in Spring Boot and Spring Cloud 它说那个
如果您的方法执行是触发初始化的方法, 然后它甚至发生在同一个线程中。
这是我的代码, TestConfigBean :
package com.my.springdemo.chapter3.test;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Data
@RefreshScope
public class TestConfig {
@Value("${name}")
private String name;
@PostConstruct
private void print(){
System.out.println("配置为=" + name);
}
}
控制器:
package com.my.springdemo.chapter3.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ConditionalOnClass(ContextRefresher.class)
@RestController
public class TestController {
@Autowired
private TestConfig config;
@Autowired
private ContextRefresher contextRefresher;
@RequestMapping("/config")
public String config(){
System.out.println("before config= " + config.getName() + ", hasCode=" + config.hashCode());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
contextRefresher.refresh();
System.out.println("After config= " + config.getName() + ", hasCode=" + config.hashCode());
return config.getName();
}
}
然后获取网址:http://localhost:8080/config,并在线程休眠时间(ID 10秒)内更改“ application.properties ”中的配置“ name ”如代码所示。)
事实证明,配置“ name ”之前和之后都有所改变。 为什么?我以错误的方式接受@RefreshScope吗?
答案 0 :(得分:1)
这是@RefreshScope
bean的预期行为。
就像文件说的那样
如果事情变得非常繁忙,同一个线程中同一个bean上的两个连续方法执行可能会应用于不同的目标。
@RefreshScope
bean不保证同一线程上的多次调用将使用相同的目标bean。
在您的示例中,您调用contextRefresher.refresh();
,它将销毁所有刷新范围的bean。第二次调用config.getName()
将再次重新初始化bean。这就是为什么你在两次调用之间更改配置的情况下获得不同名称的原因。
如果您的方法执行是触发初始化的方法,那么它甚至都发生在同一个线程中。
上面的语句只是意味着bean初始化本身将在同一个线程上执行。它并不意味着您的两个调用将使用相同的目标。
恕我直言,使用@RefreshScope
对某些案件来说可能有点风险。
评论中的问题更新
恕我直言,@ConfigurationProperties
注释也在Spring Cloud中得到特别处理。如果发生EnvironmentChangedEvent
,则使用@ConfigurationProperties
注释的Spring bean将使用更改的值重新绑定。
Spring Cloud中的@ConfigurationProperties
与@RefreshScope
bean之间的主要区别在于此过程中的原子性。
Spring Cloud只为@ConfigurationProperties
带注释的bean启动重新绑定过程,而不会在EnvironmentChangedEvent
发生时创建新的bean实例。这意味着在此过程中(即在此过程结束之前)可能会发生对此bean的任何调用。因此,此bean的用户可以看到任何中间状态(前三个属性已更改。但是应用了两个属性值,并且尚未应用一个属性。在此状态下可以进行任何调用)
如果使用@RefreshScope
注释,则会创建一个代理bean,而不是实际的目标bean。如果刷新bean(通过调用refresh()API或其他方式),则会从缓存中删除实际的目标bean。如果发生对bean的任何下一次调用,则重新创建目标bean并再次初始化(此过程由锁同步)。因此,对bean的任何调用总是发生在bean的稳定状态(完成初始化bean之后)
您可以使用@ConfigurationProperties
注释@RefreshScope
bean。或者,您只能在您的bean上使用@RefreshScope
注释,并在其内部字段中添加@Value
注释。
无论如何,即使在同一个线程上,@ConfigurationProperties
和@RefreshScope
都不能保证多次调用的预期结果。希望这会有所帮助。