Spring在PhysicalNamingStrategy实现中不注入带有@Value或@Autowired注释的变量。

huangapple go评论79阅读模式
英文:

Spring not injecting @Value or @Autowired annotated variables in PhysicalNamingStrategy Implementations:

问题

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;

@Component
public class PhysicalNamingStrategyImpl implements PhysicalNamingStrategy, Serializable {

    private static final long serialVersionUID = 2389476641866177676L;

    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;
        }
        // ... (rest of the method)
    }

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        logger.debug("toPhysicalTableName: {} with primaryTableName : {}, secondaryTableName : {}", name, primaryTableName , secondaryTableName );
        if (name == null) {
            return null;
        }
        // ... (rest of the method)
    }

    @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;
    }
}

Please note that the code provided above is a translation of the code snippet you provided. If you have any further questions or need assistance with this code, feel free to ask.

英文:

I am struggling to get my PhysicalNamingStrategy Implementation in a Spring Boot + Hibernate Project to work as expected. The problem is that both, @Value and @Autowired annotated variables are always null / not properly injected with values from my application.properties. I need this in order to be able to externalize parameters like schema and table names and i can't use the fixed variant like this:

@Entity
@Table(name = "table_name", schema = "primary_schema")

Well actually I do, but the PhysicalNamingStrategy comes in and "translates" the static names to the parameterized names. At least that is what should happen.

I am 3/4 sure, that Spring is aware of my Class (Package and Class is scanned / found via ComponentScan) because when I create duplicates I get an expected Exception during bootup telling me that Spring found 2 identical beans. So I have no clue why the variables are not injected properly in this Class. Other classes (in the same and in other packages!) work fine with @Value and @Autowired annotations.

My project structure looks like this (reduced to the relevant parts):

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

I am using:

- 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

I configured Spring to use that Naming Strategy Implementation in the application.properties using this parameter:

spring.jpa.properties.hibernate.physical_naming_strategy=org.packagename.configuration.PhysicalNamingStrategyImpl

The Class is definitly used because i see the expected Log-Outputs as well as reach my breakpoints in the methods of the Class. So up until here everything is working as it should.
But the @Value annotated variables are always null while in other Classes the same values have the expected values from the properties file.

Here is the (test) class in Question (added those manual variable initialization after the //FIXME Comments in order to make it work at all, this will be removed as soon as the injection is working):

<!-- language: java -->

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(&quot;${app.primary.schema.name}&quot;)
private String primarySchemaName;
@Value(&quot;${app.primary.table.name}&quot;)
private String primaryTableName;
@Value(&quot;${app.secondary.schema.name}&quot;)
private String secondarySchemaName;
@Value(&quot;${app.secondary.table.name}&quot;)
private String secondaryTableName;
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) {
logger.debug(&quot;toPhysicalSchemaName: {} with primarySchemaName: {}, secondarySchemaName: {}&quot;, name, primarySchemaName, secondarySchemaName);
if (name == null) {
return null;
}
// FIXME @Value always null.... 
primarySchemaName = &quot;ACTUAL_SCHEMA_NAME&quot;;
secondarySchemaName = &quot;ACTUAL_SCHEMA_NAME2&quot;;
switch (name.getText()) {
case &quot;primary_schema&quot;:
return new Identifier(primarySchemaName, name.isQuoted());
case &quot;secondary_schema&quot;:
return new Identifier(secondarySchemaName, name.isQuoted());
default:
return name;
}
}
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
logger.debug(&quot;toPhysicalTableName: {} with primaryTableName : {}, secondaryTableName : {}&quot;, name, primaryTableName , secondaryTableName );
if (name == null) {
return null;
}
// FIXME @Value always null....
primaryTableName = &quot;ACTUAL_TABLE_NAME&quot;;
secondaryTableName = &quot;ACTUAL_TABLE_NAME2&quot;;
switch (name.getText()) {
case &quot;table_name&quot;:
return new Identifier(syncLogTableTableName, name.isQuoted());
case &quot;table_name2&quot;:
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;
}
}

I am not instantiating this Class manually (no new PhysicalNamingStrategyImpl()) in the Code of my project so it should be handled completly by Spring itself. But I am not sure how, where and when does Spring create this Class during boot.

答案1

得分: 1

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

@Component
public class SomeComponent {

    private static SomeComponent selfInstance;

    // 在此处添加您的 @Value 属性

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

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

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

英文:

Naming strategy is not instantiated as a spring component. You can use a helper component to inject the properties and get the instance in a static way:

@Component
public class SomeComponent {
private static SomeComponent selfInstance;
// Your @Value properties here
@PostConstruct
public void init() {
selfInstance = this;
}
public static SomeComponent getInstance() {
return selfInstance;
}
}

Then in your naming strategy: SomeComponent.getInstance().getXX

huangapple
  • 本文由 发表于 2020年9月30日 23:52:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/64141279.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定