Spring Boot :如何动态设置Spring属性

pieyvz9o  于 2023-04-19  发布在  Spring
关注(0)|答案(4)|浏览(205)

有很多属性可以在application.propertiesSping Boot 应用程序的www.example.com中定义。
但是我想传递属性来配置ssl从代码内部弹出。

server.ssl.enabled=true
# The format used for the keystore 
server.ssl.key-store-type=PKCS12
# The path to the keystore containing the certificate
server.ssl.key-store=keys/keystore.jks
# The password used to generate the certificate
server.ssl.key-store-password=changeit
# The alias mapped to the certificate
server.ssl.key-alias=tomcat

因为这些将是spring定义的属性,从application.properties中使用。我只想根据一些逻辑从代码中设置它们。
对于非Spring应用程序,我仍然有一些想法,它们可以作为application,session或context属性传递,但我不知道这在Spring中是如何工作的。
任何帮助将不胜感激。

lc8prwob

lc8prwob1#

既然你知道在spring Boot 应用中启用SSL的属性。你可以在spring boot应用中以编程方式传递这些属性,如下所示:

@SpringBootApplication
public class SpringBootTestApplication {
    public static void main(String[] args) {

//      SpringApplication.run(SpringBootTestApplication.class, args);

        Properties props = new Properties();
        props.put("server.ssl.key-store", "/home/ajit-soman/Desktop/test/keystore.p12");
        props.put("server.ssl.key-store-password", "123456");
        props.put("server.ssl.key-store-type", "PKCS12");
        props.put("server.ssl.key-alias", "tomcat");

        new SpringApplicationBuilder(SpringBootTestApplication.class)
            .properties(props).run(args);
    }
}

正如你所看到的,我已经评论了这一点:SpringApplication.run(SpringBootTestApplication.class, args);并使用SpringApplicationBuilder类向应用程序添加属性。
现在,这些属性已在程序中定义,您可以根据需要应用条件并更改属性值。

alen0pnh

alen0pnh2#

在Sping Boot 中,您可以使用System.getProperty(String key)System.setProperty(String key, String value)读取和编辑属性

public static void main(String[] args) {

    // set properties
    System.setProperty("server.ssl.enabled", "true");
    System.setProperty("server.ssl.key-store-type", "PKCS12");
    System.setProperty("server.ssl.key-store", "keys/keystore.jks");
    System.setProperty("server.ssl.key-store-password", "changeit");
    System.setProperty("server.ssl.key-alias", "tomcat");

    // run
    SpringApplication.run(DemoApplication.class, args);
}

备注

这将覆盖静态属性(除了被覆盖的属性之外,不是全部)。

yzuktlbb

yzuktlbb3#

您需要像这样定义和注册ApplicationListener:

public class DynamicPropertiesListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
  public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    ConfigurableEnvironment environment = event.getEnvironment();
    // modify the properties here, see the ConfigurableEnvironment javadoc
  }
}

现在注册监听器。如果使用main方法运行应用程序:

SpringApplication app = new SpringApplication(primarySources);
app.addListeners(new DynamicPropertiesListener());
app.run(args);

或者,更好的方法是创建包含以下内容的src\main\resources\META-INF\spring.factories文件:

org.springframework.context.ApplicationListener=x.y.DynamicPropertiesListener

其中x.y是监听器的包。

ctehm74n

ctehm74n4#

要添加另一个选项,您可以实现一个BeanPostProcessor类。它提供两个方法:
postProcessAfterInitializationpostProcessBeforeInitialization
工厂钩子,允许对新bean示例进行自定义修改-例如,检查标记接口或使用代理 Package bean。通常,通过标记接口等填充bean的后处理器将实现postProcessBeforeInitialization(java.lang.Object,java.lang.String),而使用代理 Package bean的后处理器通常将实现postProcessAfterInitialization(java.lang.Object,java.lang.String)。
我正在使用Sping Boot 和Spring Kafka,我只想更改本地配置文件。
在我的代码示例中,我使用它来覆盖Kafka Location属性,因为对于SSL,它不从classpath读取。
代码是这样的:

import io.confluent.kafka.schemaregistry.client.SchemaRegistryClientConfig;
import java.io.IOException;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.kafka.common.config.SslConfigs;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

@Configuration
@RequiredArgsConstructor
public class KafkaConfiguration implements BeanPostProcessor {

  @Value("${spring.kafka.ssl.key-store-location:}")
  private Resource keyStoreResource;
  @Value("${spring.kafka.properties.schema.registry.ssl.truststore.location:}")
  private Resource trustStoreResource;
  private final Environment environment;

  @SneakyThrows
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof KafkaProperties) {
      KafkaProperties kafkaProperties = (KafkaProperties) bean;
      if(isLocalProfileActive()) {
        configureStoreLocation(kafkaProperties);
      }
    }
    return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
  }

  private boolean isLocalProfileActive() {
    return Arrays.stream(environment.getActiveProfiles()).anyMatch(profile -> "local".equals(profile));
  }

  private void configureStoreLocation(KafkaProperties kafkaProperties) throws IOException {
    kafkaProperties.getSsl().setKeyStoreLocation(new FileSystemResource(keyStoreResource.getFile().getAbsolutePath()));
    kafkaProperties.getProperties().put(SchemaRegistryClientConfig.CLIENT_NAMESPACE + SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG, keyStoreResource.getFile().getAbsolutePath());
    kafkaProperties.getSsl().setTrustStoreLocation(new FileSystemResource(trustStoreResource.getFile().getAbsolutePath()));
    kafkaProperties.getProperties().put(SchemaRegistryClientConfig.CLIENT_NAMESPACE + SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, trustStoreResource.getFile().getAbsolutePath());
  }

}

这样我就可以在我的属性文件中:
spring.kafka.ssl.key-store-location=classpath:mykeystore.jks
代码将从中获取绝对路径并设置它。它还可以根据配置文件进行过滤。
需要强调的是,BeanPostProcessor会为Everybean运行,因此请确保过滤所需的内容。

相关问题