Java 如何保护@ConfigurationProperties类免受更改?
要使用Java 如何保护@ConfigurationProperties类免受更改?,java,spring,spring-boot,configurationproperty,Java,Spring,Spring Boot,Configurationproperty,要使用@ConfigurationProperties注释,必须创建一个具有如下getter和setter的类: @ConfigurationProperties(prefix = "some") public class PropertiesConfig { private boolean debug; public boolean isDebug() { return debug; } public void setDebug(boolea
@ConfigurationProperties
注释,必须创建一个具有如下getter和setter的类:
@ConfigurationProperties(prefix = "some")
public class PropertiesConfig {
private boolean debug;
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}
但这会导致有人试图通过调用以下命令来修改此值:
@Autowire
private PropertiesConfig config;
//....
config.setDebug(true);
有没有一种方法可以创建
@ConfigurationProperties
注释类,而不使用setter和外部解析器/读取器类 不可能开箱即用@ConfigurationProperties
bean必须具有标准的getter和setter。你可能想考虑这个答案中描述的方法:
或者像这样:
@Component
public class ApplicationProperties {
private final String property1;
private final String property2;
public ApplicationProperties(
@Value("${some.property1"}) String property1,
@Value("${some.other.property2}) String property2) {
this.property1 = property1;
this.property2 = property1;
}
//
// ... getters only ...
//
}
一种尽可能少使用样板代码的方法是只使用带有getter的接口
public interface AppProps {
String getNeededProperty();
}
在Lombok的@Getter
和@Setter
注释的帮助下,在实现中摆脱样板文件的Getter和Setter:
@ConfigurationProperties(prefix = "props")
@Getter
@Setter
public class AppPropsImpl implements AppProps {
private String neededProperty;
}
那么,对于bean Bean只能通过接口访问其他bean,可以将其标记为<代码> @组件< /代码>,或者在主应用程序类上使用<代码> @ EnablCon图形属性(AppPlimpll.class)< /Cl>,将其放入一个配置中,该接口将通过接口:
公开它。@Configuration
@EnableConfigurationProperties
public class PropsConfiguration {
@Bean
public AppProps appProps(){
return new AppPropsImpl();
}
}
现在这个bean只能通过使用接口注入,这使得setter对其他bean不可用:
public class ApplicationLogicBean {
@Autowired
AppProps props;
public void method(){
log.info("Got " + props.getNeededProperty());
}
}
使用Spring Boot 1.5.3和Lombok 1.16.16进行了测试。类似的功能很好
@Configuration
class MyAppPropertiesConfiguration {
@Bean
@ConfigurationProperties(prefix = "some")
public PropertiesConfig propertiesConfig () {
return new PropertiesConfigImpl();
}
public interface PropertiesConfig {
public boolean isDebug();
}
private static class PropertiesConfigImpl implements PropertiesConfig {
private boolean debug;
@Override
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}
}
然后
@Autowired PropertiesConfig properties;
从SpringBoot2.2开始,最终可以定义用
@ConfigurationProperties
修饰的不可变类。非常感谢Spring开发人员不断改进他们的框架。显示了一个示例。
您只需要声明一个包含要绑定的字段的构造函数(而不是setter方式): 注1:您必须使用要绑定的参数定义一个且仅定义一个构造函数: 在这个设置中,必须使用 要绑定的属性列表,而不是除 构造函数中的那些是绑定的 注2:引入了
@DefaultValue
来定义不可变属性绑定的默认值
可以使用@DefaultValue和相同的方法指定默认值
将应用转换服务将字符串值强制为
缺少属性的目标类型
以下是从官方文档中获得的更详细示例:
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DefaultValue;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}
导入java.net.InetAddress;
导入java.util.List;
导入org.springframework.boot.context.properties.ConfigurationProperties;
导入org.springframework.boot.context.properties.DefaultValue;
导入org.springframework.boot.context.properties.ConstructorBinding;
@构造绑定
@配置属性(“acme”)
公共类AcmeProperties{
启用私有最终布尔值;
专用最终地址远程地址;
私人最终担保;
公共AcmeProperties(启用布尔值、InetAddress远程地址、安全性){
this.enabled=已启用;
this.remoteAddress=远程地址;
安全=安全;
}
公共布尔值isEnabled(){…}
公共地址getRemoteAddress(){…}
公共安全getSecurity(){…}
公共静态类安全{
私有最终字符串用户名;
私有最终字符串密码;
私人最终名单角色;
公共安全(字符串用户名、字符串密码、,
@默认值(“用户”)列表(角色){
this.username=用户名;
this.password=密码;
this.roles=角色;
}
公共字符串getUsername(){…}
公共字符串getPassword(){…}
公共列表getRoles(){…}
}
}
不幸的是,有两种极端情况不适用于这种方法。例如,使用@Value
将应用程序.yaml
中的对象作为映射
注入,当它使用@ConfigurationProperties
方法按预期工作时,将无法工作。我必须将接口移动到它自己的文件中。然后这个效果很好。
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DefaultValue;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}