【发布时间】:2020-09-30 15:52:36
【问题描述】:
我正在努力让我在 Spring Boot + Hibernate 项目中的 PhysicalNamingStrategy 实现按预期工作。问题是@Value 和@Autowired 注释变量始终为空/未正确注入来自我的application.properties 的值。我需要这个以便能够将架构和表名等参数外部化,并且我不能使用这样的固定变体:
@Entity
@Table(name = "table_name", schema = "primary_schema")
实际上我是这样做的,但是 PhysicalNamingStrategy 进来并将静态名称“翻译”为参数化名称。至少这是应该发生的。
我有 3/4 的把握,Spring 知道我的类(通过 ComponentScan 扫描/找到包和类),因为当我创建重复项时,我在启动期间收到预期的异常,告诉我 Spring 找到了 2 个相同的 bean。所以我不知道为什么在这个类中没有正确注入变量。其他类(在相同和其他包中!)与 @Value 和 @Autowired 注释一起工作。
我的项目结构如下(简化为相关部分):
project/src/main/java/
----------------------org.packagename
-------------------------configuration
-----------------------------BeanConfig.java
-----------------------------DataSourceConfiguration.java
-----------------------------PhysicalNamingStrategyImpl.java
-------------------------constant
-------------------------controller
-------------------------exception
-------------------------model
-------------------------repository
-------------------------scheduler
-------------------------service
-------------------------AppMainClass.java
project/src/main/resources
----------------------application.properties
----------------------application-devel.properties
----------------------application-prod.properties
----------------------schema-h2.sql
----------------------log4j2.xml
我正在使用:
- spring-boot-2.3.2 (multiple dependencies like spring-boot-autoconfigure, etc.)
- spring-5.2.8 (multiple dependencies like spring-beans, etc.
- hibernate-5.4.18
我使用此参数将 Spring 配置为在 application.properties 中使用该命名策略实现:
spring.jpa.properties.hibernate.physical_naming_strategy=org.packagename.configuration.PhysicalNamingStrategyImpl
该类被明确使用,因为我看到了预期的日志输出,并在该类的方法中达到了我的断点。所以直到这里一切都在正常工作。
但是@Value 注释变量始终为空,而在其他类中,相同的值具有属性文件中的预期值。
这是问题中的(测试)类(在//FIXME 注释之后添加了那些手动变量初始化以使其完全正常工作,一旦注入工作,它将被删除):
package org.packagename.configuration;
import java.io.Serializable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* //stripped
*/
@Component
public class PhysicalNamingStrategyImpl implements PhysicalNamingStrategy, Serializable {
//public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {
/** */
private static final long serialVersionUID = 2389476641866177676L;
// public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();
private Logger logger = LogManager.getLogger(PhysicalNamingStrategyImpl.class);
@Value("${app.primary.schema.name}")
private String primarySchemaName;
@Value("${app.primary.table.name}")
private String primaryTableName;
@Value("${app.secondary.schema.name}")
private String secondarySchemaName;
@Value("${app.secondary.table.name}")
private String secondaryTableName;
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) {
logger.debug("toPhysicalSchemaName: {} with primarySchemaName: {}, secondarySchemaName: {}", name, primarySchemaName, secondarySchemaName);
if (name == null) {
return null;
}
// FIXME @Value always null....
primarySchemaName = "ACTUAL_SCHEMA_NAME";
secondarySchemaName = "ACTUAL_SCHEMA_NAME2";
switch (name.getText()) {
case "primary_schema":
return new Identifier(primarySchemaName, name.isQuoted());
case "secondary_schema":
return new Identifier(secondarySchemaName, name.isQuoted());
default:
return name;
}
}
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
logger.debug("toPhysicalTableName: {} with primaryTableName : {}, secondaryTableName : {}", name, primaryTableName , secondaryTableName );
if (name == null) {
return null;
}
// FIXME @Value always null....
primaryTableName = "ACTUAL_TABLE_NAME";
secondaryTableName = "ACTUAL_TABLE_NAME2";
switch (name.getText()) {
case "table_name":
return new Identifier(syncLogTableTableName, name.isQuoted());
case "table_name2":
return new Identifier(assetExportDataTableName, name.isQuoted());
default:
return name;
}
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment context) {
return name;
}
}
我没有在我的项目代码中手动实例化这个类(没有new PhysicalNamingStrategyImpl()),所以它应该由 Spring 本身完全处理。但我不确定 Spring 在启动期间如何、在何处以及何时创建这个类。
【问题讨论】:
-
命名策略不是春豆。因此,您不能将值注入其中。
-
已经尝试过这里描述的方法:stackoverflow.com/questions/49148172/… 但也无法使其正常工作(无法确定为属性
spring.jpa.properties.hibernate.physical_naming_strategy设置的正确值以使其使用而是这个策略)。
标签: java spring spring-boot hibernate