在执行中使用@RefreshScope 时如何保持数据一致
how to keep data consistent when using @RefreshScope in a execution
我读了这个Dynamic Configuration Properties in Spring Boot and Spring Cloud
它说
If your method execution is the one that triggers the initialization,
then it all even happens in the same thread.
这是我的代码,一个 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();
}
}
然后得到url:http://localhost:8080/config,并在我的“application.properties[=”中更改配置“name” 30=]" 在线程休眠期间(代码显示为 10 秒)。
原来是配置“name”前后发生了变化。
为什么?我是否以错误的方式使用@RefreshScope?
这是 @RefreshScope
bean 的预期行为。
正如文件所说
Two consecutive method executions on the same bean in the same thread may be applied to different targets if things get really busy.
@RefreshScope
bean 不保证您在同一线程上的多次调用将使用相同的目标 bean。
在您的示例中,您调用 contextRefresher.refresh();
它将销毁所有刷新作用域的 bean。您第二次调用 config.getName()
将再次重新初始化您的 bean。这就是为什么您在两次调用之间更改配置时获得不同名称的原因。
If your method execution is the one that triggers the initialization, then it all even happens in the same thread.
以上语句只是意味着bean初始化本身将在同一个线程上执行。这并不意味着您的两次调用将使用相同的目标。
恕我直言,在某些情况下使用 @RefreshScope
可能会有一点风险。
更新评论中的问题
恕我直言,@ConfigurationProperties
注释在 Spring 云中也经过特殊处理。如果出现 EnvironmentChangedEvent
,则使用 @ConfigurationProperties
注释的 Spring 个 bean 将 re-binded 具有更改的值。
Spring Cloud 中的 @ConfigurationProperties
和 @RefreshScope
bean 之间的主要区别是过程中的原子性。
Spring Cloud 只是在 EnvironmentChangedEvent
发生时开始重新绑定 @ConfigurationProperties
注释 bean 的过程,而不创建新的 bean 实例。这意味着对此 bean 的任何调用都可以在此过程中发生(即在此过程结束之前)。结果,此 bean 的用户可以看到任何中间状态(例如更改了三个属性。但是应用了两个属性值,一个 属性 尚未应用。任何调用都可以在此状态下发生)
在使用 @RefreshScope
注释的情况下,将创建一个代理 bean 并将其注入而不是实际的目标 bean。如果该 bean 被刷新(通过调用 refresh() API 或其他方式),您的实际目标 bean 将从缓存中删除。如果对您的 bean 进行任何下一次调用,您的目标 bean 将 re-created 并再次初始化(并且此过程由锁同步)。因此,您对 bean 的任何调用总是在 bean 的稳定状态下发生(在完成初始化 bean 之后)
您可以使用 @RefreshScope
注释您的 @ConfigurationProperties
bean。或者您只能在 bean 中使用 @RefreshScope
注释,在其内部字段上使用 @Value
注释。
无论如何,即使在同一线程上,@ConfigurationProperties
和 @RefreshScope
都不能保证多次调用的预期结果。希望这有帮助。
我读了这个Dynamic Configuration Properties in Spring Boot and Spring Cloud 它说
If your method execution is the one that triggers the initialization, then it all even happens in the same thread.
这是我的代码,一个 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();
}
}
然后得到url:http://localhost:8080/config,并在我的“application.properties[=”中更改配置“name” 30=]" 在线程休眠期间(代码显示为 10 秒)。
原来是配置“name”前后发生了变化。 为什么?我是否以错误的方式使用@RefreshScope?
这是 @RefreshScope
bean 的预期行为。
正如文件所说
Two consecutive method executions on the same bean in the same thread may be applied to different targets if things get really busy.
@RefreshScope
bean 不保证您在同一线程上的多次调用将使用相同的目标 bean。
在您的示例中,您调用 contextRefresher.refresh();
它将销毁所有刷新作用域的 bean。您第二次调用 config.getName()
将再次重新初始化您的 bean。这就是为什么您在两次调用之间更改配置时获得不同名称的原因。
If your method execution is the one that triggers the initialization, then it all even happens in the same thread.
以上语句只是意味着bean初始化本身将在同一个线程上执行。这并不意味着您的两次调用将使用相同的目标。
恕我直言,在某些情况下使用 @RefreshScope
可能会有一点风险。
更新评论中的问题
恕我直言,@ConfigurationProperties
注释在 Spring 云中也经过特殊处理。如果出现 EnvironmentChangedEvent
,则使用 @ConfigurationProperties
注释的 Spring 个 bean 将 re-binded 具有更改的值。
Spring Cloud 中的 @ConfigurationProperties
和 @RefreshScope
bean 之间的主要区别是过程中的原子性。
Spring Cloud 只是在 EnvironmentChangedEvent
发生时开始重新绑定 @ConfigurationProperties
注释 bean 的过程,而不创建新的 bean 实例。这意味着对此 bean 的任何调用都可以在此过程中发生(即在此过程结束之前)。结果,此 bean 的用户可以看到任何中间状态(例如更改了三个属性。但是应用了两个属性值,一个 属性 尚未应用。任何调用都可以在此状态下发生)
在使用 @RefreshScope
注释的情况下,将创建一个代理 bean 并将其注入而不是实际的目标 bean。如果该 bean 被刷新(通过调用 refresh() API 或其他方式),您的实际目标 bean 将从缓存中删除。如果对您的 bean 进行任何下一次调用,您的目标 bean 将 re-created 并再次初始化(并且此过程由锁同步)。因此,您对 bean 的任何调用总是在 bean 的稳定状态下发生(在完成初始化 bean 之后)
您可以使用 @RefreshScope
注释您的 @ConfigurationProperties
bean。或者您只能在 bean 中使用 @RefreshScope
注释,在其内部字段上使用 @Value
注释。
无论如何,即使在同一线程上,@ConfigurationProperties
和 @RefreshScope
都不能保证多次调用的预期结果。希望这有帮助。