英文:
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("${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;
}
}
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论