Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何保护@ConfigurationProperties类免受更改?_Java_Spring_Spring Boot_Configurationproperty - Fatal编程技术网

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() { ... }

    }

}