【问题标题】:How to dynamically choose the configurations based on the environment in JAVA?JAVA中如何根据环境动态选择配置?
【发布时间】:2017-06-06 06:48:30
【问题描述】:

我有一个实用程序类,它具有与电子邮件发件人相关的常见配置,配置会根据StagingProduction 等环境而变化。现在如何根据环境动态选择配置?

这是我的代码,

EmailUtility.java

package com.housecar.common;

public class EmailUtility {

 //For staging 
 public static final String FROM_EMAIL_ID = "xx12@xyz.com";
 public static final String FROM_NAME = "xyz";
 static final String SMTP_USERNAME = "xx12@xyz.com";
 static final String SMTP_PASSWORD = "15sss67$";
 public static final String REPLY_EMAIL_ID = "xx12@xyz.com";
 public static final String MAIL_SMTP_PORT = "587";
 public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = "587";
 public static final String SMTP_HOST = "smtp.gmail.com";
 public static final String MAIL_SMTP_SOCKETFACTORY_CLASS = "javax.net.ssl.SSLSocketFactory";


 //for production

 /*public static final String FROM_EMAIL_ID = "admin@xyz.com";
 public static final String FROM_NAME = "xyz";
 static final String SMTP_USERNAME = "AKYeeeELEQAGAA"; // Replace with
                                                            // your SMTP
                                                            // username.
 static final String SMTP_PASSWORD = "gvwwwwwbgpGm/C/LmUYUK5HosQar7mTSwjl5MFeBRR";
 public static final String REPLY_EMAIL_ID = "admin@xyz.com";
 public static final String MAIL_SMTP_PORT = "587";
 public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = "587";
 public static final String SMTP_HOST = "email-smtp.us-east-1.amazonaws.com";
 public static final String MAIL_SMTP_SOCKETFACTORY_CLASS = "javax.net.ssl.SSLSocketFactory";*/

}

在我的代码中,我手动注释掉了配置!

【问题讨论】:

  • 您应该查看属性文件。
  • 你没有使用任何属性文件或类似的东西。 ??
  • 动态是什么意思?在运行应用程序时或仅通过任何启动更改配置?
  • 您可以创建一个属性文件,然后根据您的目的读取它,例如用于生产production.mail.smtp.port=587 和暂存staging.mail.smtp.port=587
  • 将属性添加到application.properties 在开始之前根据 evn 定义它们。例如:from.email.id = xx12@xyz.com 并将属性注入您的实用程序类。

标签: java spring spring-boot constants


【解决方案1】:

您可以使用属性文件来解决您的问题,就像您可以根据环境有两个属性文件。

1) config_staging.properties 2) config_production.properties

将暂存电子邮件配置移至 config_staging.properties,将生产配置移至 config_production.properties。

这将在运行应用程序时进行配置。

例如,

config_staging.properties

 smtp.username = "xx12@xyz.com";
 smtp.password = "15sss67$";

config_production.properties

smtp.username = "AKYeeeELEQAGAA";
smtp.password = "gvwwwwwbgpGm/C/LmUYUK5HosQar7mTSwjl5MFeBRR";

然后将它们注入到 EmailUtility 类中,

@Value("${smtp.username}")
private String smtpUsername;


@Value("${smtp.password}")
private String smtpPassword;

【讨论】:

    【解决方案2】:

    您应该从属性存储中查找系统依赖值(例如,由 Javas Properties 类处理的属性文件)。

    但您不应在同一个文件中提供所有系统信息。

    您应该有单独的文件(同名),并让您的部署过程将目标系统的文件复制到预期位置。

    通过这种方式,您可以让运营团队使用您(作为开发人员)不应该知道的数据来操作(或预配置)属性文件,例如。高安全性系统的密码...

    【讨论】:

      【解决方案3】:

      将以下内容添加到您的 application.properties 文件中:

      from.email.id = xx12@xyz.com
      from.name = xyz
      
      ...
      

      e.t.c

      您在启动应用程序之前定义这些属性(取决于您的情况)。 当然,您需要将它们注入到您的类中,如下所示:

      @Value("${from.email.id}")
      private String fromEmailId;
      

      所以现在fromEmailId 将具有赋予application.properties 文件的值。

      祝你好运。

      编辑:

      如果您想要更高级别的安全性,您可以使用jasypt 将您的密码写入您的applicaiton.properties 文件中。最后,密码将如下所示:

      smtp.password = ENC(5KZL2q+Ute21FzCsJy/h0aIp75TZgHBHx8L11R+jTJs0=)
      

      【讨论】:

      • 你在最后一行的application.properties 中有错字
      【解决方案4】:

      在 spring 中,您可以使用 propertiesyaml 设置外部配置。

      否则,如果您在运行应用程序时需要更改配置并且您正在使用数据库,您可以在您的数据库中创建一个带有键值配置的配置表,并在您的代码中读取它们。

      例如,像这样的一张表:

      CREATE TABLE configuration (
          key varchar(255),
          value varchar(255)
      );
      

      其中key 是属性名称,value 是属性值。

      一个属性

      environment=development
      

      可能变成

      INSERT INTO configuration (key, value) VALUES('environment', 'development');
      

      【讨论】:

        【解决方案5】:

        这里的其他答案是朝着正确方向迈出的一步。

        有些人建议将配置值移动到.properties 文件中。这是朝着正确方向迈出的一大步,但忽略了您正在使用 Spring Boot 的事实。

        有些人建议将配置值移动到 Spring application.propertiesapplication.yaml 文件中。这是 Spring 应用程序的更好选择。 application.properties 实际上只是一个 .properties 文件,就像最初建议的那样,但由 Spring Framework 自动加载。这在Spring Boot Reference GuideChapter 24. Externalized Configuration 中都有描述。

        但是,你的问题实际上是说:

        [...] 常见配置 与电子邮件发件人相关,配置会根据 Staging 和 Production 等环境而变化。

        Spring 有一个非常好的特性,你可以在其中拥有一组配置文件(甚至是单个.yaml 文件),并且框架会根据应用程序运行的位置自动加载适当的配置值,在分期或生产。这一切都在Chapter 25. Profiles 中进行了描述。

        【讨论】:

          【解决方案6】:

          application-{profile}.propertiesapplication-{profile}.yml 允许您根据弹簧配置文件自定义您的应用程序。

          可以使用以下方法仅在 {profile} 中创建 bean:

          @Service
          @Profile(profile-name)
          public class ServiceImpl implements ServiceInterface {
          }
          

          还可以根据属性值和条件创建 bean。

          @Bean
          @ConditionalOnProperty(prefix = EmailProperties.PREFIX, name = "fromId")
          public BeanClass bean() {
              return new BeanClass(okHttpProperties.getFromId());
          }
          

          条件bean可以基于表达式

          @Bean
          @ConditionalOnExpression("'${spring.datasource.driver-class-name}'=='com.mysql.jdbc.Driver'")
          public DbUtil dbMysqlUtil() {
              ...
          }
          
          @Bean
          @ConditionalOnExpression("'${spring.datasource.driver-class-name}'=='org.hsqldb.jdbc.JDBCDriver'")
          public DbUtil dbHsqlUtil() {
              ...
          }
          

          【讨论】:

            【解决方案7】:

            将 configuration.properties 文件分开用于舞台和制作。这些配置文件将具有相应的属性。现在,在应用程序启动时,您可以先读取基于环境的属性。您可以在应用程序中作为参数传递的环境值。您只需要编写一个简单的ConfigurtionReader 类,它将在应用程序启动之前读取所需的配置。下面是考虑在纯 java 中读取一个非常简单的属性文件的代码示例。

            这将读取与 jar(当前应用程序)平行放置的属性文件。

            public class ConfigurationReader {
            
                /** The job config prop. */
                private static final Properties JOB_CONFIG_PROP = new Properties();
            
                /**
                 * Function is used to read configuration file that is placed in same place
                 * where project jar is located.
                 * 
                 */
                public void readConfiguration(final String jobName) {
                    File jarPath;
                    String propertiesPath = " ";
                    String jobConfigFile = " ";
                    try {
                        jarPath = new File(ConfigurationReader.class.getProtectionDomain().getCodeSource().getLocation().getPath());
                        propertiesPath = jarPath.getParentFile().getAbsolutePath();
                        jobConfigFile = propertiesPath + File.separator + AppConstants.CONFIGURATION_FOLDER_NAME
                                + File.separator + jobName + AppConstants.PROP;
                        JOB_CONFIG_PROP.load(new FileInputStream(jobConfigFile));
                    } catch (FileNotFoundException fileNtFoundExep) {
                        throw fileNtFoundExep;
                    } catch (IOException iOException) {
                        throw iOException;
                    } catch (Exception exception) {
                        throw exception;
                    }
                }
            
                public static String getPropertyValue(final String key) {
                    return JOB_CONFIG_PROP.getProperty(key);
                }
            
                public static void setPropertyValue(final String key, final String value) {
                    JOB_CONFIG_PROP.setProperty(key, value);
                }
            }
            

            然后您可以使用...获取/设置属性值

            ConfigurationReader.getPropertyValue("abc");
            ConfigurationReader.setPropertyValue("abc","xyz");
            

            这只是实现从属性文件中读取属性的一种简单方法。你可以这样做。

            【讨论】:

              【解决方案8】:

              这两种方法我都用过:

              1. 指定活动配置文件(例如 application-{profile}.properties) 这很好,很简单。构建过程将解析环境特定的属性文件。每个 env 的文件都可以在源代码管理中维护。 Prod 属性文件(dev/qe 无法访问)可以在源代码控制中得到保护。缺点是管理不同的属性可能会不同步(又名配置漂移)(例如,在 dev 中添加了某个属性键,但在 qe 中没有)

              2. 在运行应用程序时指定自定义参数(例如-Dapp.home) 您必须添加代码来自定义属性文件的加载。一些定制可以包括处理加密的属性值。属性键/值可以在 Chef(或等效工具)中维护。请参阅下面的示例代码:

                @Configuration
                public class MyExternalConfig {
                
                    @Bean
                    public static PropertyPlaceholderConfigurer configurer(){
                
                        //this is an external file path
                        String appHomeConfig = System.getProperty("app.home") + File.separatorChar + "config";
                
                        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
                        final Resource extResource = new FileSystemResource( new File( appHomeConfig, "application.properties") );
                        ppc.setLocations( new Resource[] { extResource } ); //add other properties file if needed
                        ppc.setIgnoreUnresolvablePlaceholders( true );
                        return ppc;
                    }
                }
                

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-02-17
                • 2021-01-26
                • 1970-01-01
                • 1970-01-01
                • 2011-08-15
                • 2017-05-05
                相关资源
                最近更新 更多