【问题标题】:Spring not injecting @Value or @Autowired annotated variables in PhysicalNamingStrategy Implementations:Spring 不在 PhysicalNamingStrategy 实现中注入 @Value 或 @Autowired 注释变量:
【发布时间】: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


【解决方案1】:

命名策略未实例化为弹簧组件。您可以使用辅助组件来注入属性并以静态方式获取实例:

@Component
public class SomeComponent {

    private static SomeComponent selfInstance;

    // Your @Value properties here

    @PostConstruct
    public void init() {
        selfInstance = this;
    }

    public static SomeComponent getInstance() {
        return selfInstance;
    }
}

然后在你的命名策略中:SomeComponent.getInstance().getXX

【讨论】:

  • 但是既然配置属性 spring.jpa.properties.hibernate.physical_naming_strategy 控制了应该使用什么类,那么你如何使用你的组件呢?
  • 这不起作用,因为只要我在命名策略中调用 SomeComponent.getInstance().getXX 就会导致 NullPointer 异常。 (SomeComponent.getInstance() 总是返回 null)。在我看来,@Value 无法注入的原因相同。就像 Spring 在创建命名策略实例时没有创建任何内容一样。
猜你喜欢
  • 1970-01-01
  • 2022-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-13
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多