如何保护@ConfigurationProperties类免受更改?

时间:2017-06-24 04:29:11

标签: java spring spring-boot configurationproperty

要使用<video>注释,必须创建一个包含getter和setter的类:

@ConfigurationProperties

但是这会导致某人试图通过调用:

修改此值
@ConfigurationProperties(prefix = "some")
public class PropertiesConfig {
    private boolean debug;

    public boolean isDebug() {
        return debug;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }
}

有没有办法在没有setter和外部解析器/ reader类的情况下创建@Autowire private PropertiesConfig config; //.... config.setDebug(true); 带注释的类?

4 个答案:

答案 0 :(得分:4)

使用尽可能少的样板代码的一种方法是使用仅具有吸气剂的接口

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,可以在主应用程序类上将其标记为@Component或使用@EnableConfigurationProperties(AppPropsImpl.class),考虑将其置于配置中它将通过接口公开它:

@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测试。

答案 1 :(得分:2)

像这样的东西可以正常使用

@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;

答案 2 :(得分:1)

不可开箱即用。 @ConfigurationProperties bean必须有标准的getter和setter。您可能需要考虑此答案中描述的方法:Immutable @ConfigurationProperties

或类似的东西:

@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 ...
  //

}

答案 3 :(得分:0)

从Spring Boot 2.2开始,最后可以定义用@ConfigurationProperties装饰的不可变类。非常感谢Spring开发人员不断改进其框架。
The documentation显示了一个示例。
您只需要声明一个带有绑定字段的构造函数(而不是setter方法):

@ConfigurationProperties(prefix = "some")
public class PropertiesConfig {
    private boolean debug;

    public AcmeProperties(boolean enabled) {
        this.enabled = enabled;   
    }

    public boolean isDebug() {
        return debug;
    }

}

注1:您必须定义一个且只有一个单个构造函数,并带有要绑定的参数:

  

在此设置中,只有一个构造函数必须与   您希望绑定的属性列表,而不是其他属性   构造函数中的绑定。

注释2:引入了@DefaultValue来定义不可变属性绑定的默认值。

  

可以使用@DefaultValue和相同的值指定默认值   转换服务将应用于将String值强制转换为   属性的目标类型。

这是从官方文档中获得的更详细的示例:

import java.net.InetAddress;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DefaultValue;

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

    }

}