簡體   English   中英

如何在spring boot中使用環境變量動態設置tableName?

[英]How to set tableName dynamically using environment variable in spring boot?

我使用 AWS ECS 來托管我的應用程序並使用 DynamoDB 進行所有數據庫操作。 因此,對於不同的環境,我將擁有具有不同表名的相同數據庫。 比如“dev_users”(用於Dev env)、“test_users”(用於Test env)等。(這是我們公司在不同環境下使用同一個Dynamo賬號的方式)

因此,我想使用通過“AWS ECS 任務定義”環境參數傳遞的環境變量來更改模型類的“tableName”。

例如。

我的模型類是:

@DynamoDBTable(tableName = "dev_users")
public class User {

現在,當我在測試環境中部署容器時,需要將“dev”替換為“test”。 我知道我可以使用

@Value("${DOCKER_ENV:dev}")

訪問環境變量。 但我不確定如何在課堂外使用變量。 有什么方法可以使用 docker env 變量來選擇我的表前綴?

我的意圖是這樣使用:

在此處輸入圖片說明

我知道這是不可能的。 但是有沒有其他方法或解決方法?

編輯1:

我正在研究 Rahul 的答案並面臨一些問題。 在寫問題之前,我將解釋我遵循的過程。

過程:

  1. 我已經在我的配置類 (com.myapp.users.config) 中創建了 bean。
  2. 由於我沒有存儲庫,因此我將模型類包名稱指定為“basePackage”路徑。 (請檢查圖像)

在此處輸入圖片說明

  • 對於 1) 我已經替換了“表名覆蓋 bean 注入”以避免錯誤。
  • 對於 2) 我打印了傳遞給此方法的名稱。 但它是空的。 所以在這里檢查所有可能的傳遞值的方法。

檢查圖像是否有錯誤:

在此處輸入圖片說明

我沒有更改我的用戶模型類中的任何內容,因為當 bean 被執行時 bean 將替換 DynamoDBTable 的名稱。 但是表名正在發生。 數據僅從模型類級別給出的表名中提取。

我在這里缺少什么?

可以通過更改的 DynamoDBMapperConfig bean 更改表名稱。

對於您必須用文字為每個表添加前綴的情況,您可以這樣添加 bean。 在您的情況下,這里的前綴可以是環境名稱。

 @Bean
public TableNameOverride tableNameOverrider() {
    String prefix = ... // Use @Value to inject values via Spring or use any logic to define the table prefix
    return TableNameOverride.withTableNamePrefix(prefix);
}

有關更多詳細信息,請查看此處的完整詳細信息: https : //github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime

關於在運行時更改表名的需要,我們也有同樣的問題。 我們使用的是 Spring-data-dynamodb 5.0.2,以下配置似乎提供了我們需要的解決方案。

首先我注釋了我的 bean 訪問器

@EnableDynamoDBRepositories(dynamoDBMapperConfigRef = "getDynamoDBMapperConfig", basePackages = "my.company.base.package")

我還設置了一個名為 ENV_PREFIX 的環境變量,它是 Spring 通過 SpEL 連接的。

@Value("#{systemProperties['ENV_PREFIX']}")
private String envPrefix;

然后我設置了一個 TableNameOverride bean:

@Bean
public DynamoDBMapperConfig.TableNameOverride getTableNameOverride() {
    return DynamoDBMapperConfig.TableNameOverride.withTableNamePrefix(envPrefix);
}

最后,我使用 TableNameOverride 注入設置了 DynamoDBMapperConfig bean。 在 5.0.2 中,我們必須在 DynamoDBMapperConfig 構建器中設置標准的 DynamoDBTypeConverterFactory 以避免 NPE。:

@Bean
public DynamoDBMapperConfig getDynamoDBMapperConfig(DynamoDBMapperConfig.TableNameOverride tableNameOverride) {
    DynamoDBMapperConfig.Builder builder = new DynamoDBMapperConfig.Builder();
    builder.setTableNameOverride(tableNameOverride);
    builder.setTypeConverterFactory(DynamoDBTypeConverterFactory.standard());
    return builder.build();
}

事后看來,我可以設置一個 DynamoDBTypeConverterFactory bean,它返回一個標准的 DynamoDBTypeConverterFactory 並使用 DynamoDBMapperConfig 構建器將它注入到 getDynamoDBMapperConfig() 方法中。 但這也將起作用。

我能夠實現以活動配置文件名稱為前綴的表名。

首先添加 TableNameResolver 類,如下所示,

@Component
public class TableNameResolver extends DynamoDBMapperConfig.DefaultTableNameResolver {

private String envProfile;

public TableNameResolver() {}

public TableNameResolver(String envProfile) {
    this.envProfile=envProfile;
}

 @Override
 public String getTableName(Class<?> clazz, DynamoDBMapperConfig config) {
  String stageName = envProfile.concat("_");
  String rawTableName = super.getTableName(clazz, config);
  return stageName.concat(rawTableName);
 }
}

然后我設置 DynamoDBMapper bean,如下所示,

@Bean
@Primary
public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB) {

    DynamoDBMapper mapper = new DynamoDBMapper(amazonDynamoDB,new DynamoDBMapperConfig.Builder().withTableNameResolver(new TableNameResolver(envProfile)).build());
     return mapper;
}

添加了變量 envProfile,它是從 application.properties 文件訪問的活動配置文件屬性值。

@Value("${spring.profiles.active}")
private String envProfile;

我對另一個答案投了贊成票,但這里有一個想法:

創建一個包含所有用戶詳細信息的基類:

@MappedSuperclass
public abstract class AbstractUser {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;

創建 2 個具有不同表名和螺旋配置文件的實現:

@Profile(value= {"dev","default"})
@Entity(name = "dev_user")
public class DevUser extends AbstractUser {
}

@Profile(value= {"prod"})
@Entity(name = "prod_user")
public class ProdUser extends AbstractUser {
}

創建一個使用映射超類的 JPA 存儲庫

public interface UserRepository extends CrudRepository<AbstractUser, Long> {
}

然后用彈簧輪廓切換植入

@RunWith(SpringJUnit4ClassRunner.class)
@DataJpaTest
@Transactional
public class UserRepositoryTest {

    @Autowired
    protected DataSource dataSource;

    @BeforeClass
    public static void setUp() {
        System.setProperty("spring.profiles.active", "prod");
    }

    @Test
    public void test1() throws Exception {

        DatabaseMetaData metaData = dataSource.getConnection().getMetaData();
        ResultSet tables = metaData.getTables(null, null, "PROD_USER", new String[] { "TABLE" });
        tables.next();
        assertEquals("PROD_USER", tables.getString("TABLE_NAME"));
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM