访问AttributeConverter类中的Spring Bean

Eff*_*kri 9 spring hibernate jpa

我正在开发一个Spring Data JPA应用程序,并且我已经创建了一个AttributeConverter类,以便ArrayList在数据库列中将对象保存为JSON.在这个类中,我需要使用我定义为Spring Bean的类.

由于AttributeConverter该类由Hibernate管理,它似乎在创建任何Spring bean之前被实例化,因此DI似乎不起作用(类中的Spring Bean AttributeConverternull,并且我正在NullPointer抛出异常).所以目前我正在创建另一个所述bean的实例,以便能够在AttributeConverter类中使用它(这违背了DI的目的).

我也尝试创建一个实现的Util类(带注释@Component)ApplicationContextAware,它提供了一个给出SpringBean(cxt.getBean(BeanClass.class))的方法.但是,这也被实例化AttributeConverter.

有什么想法可以解决这个问题吗?

谢谢.

lpa*_*zic 14

使用JPA 2.2,Spring 5.1( SPR-16305)和Hibernate 5.3.0(HHH-12135)时,您不再需要使用可变的静态属性hack,并且可以像在常规的Spring托管bean上一样使用依赖项注入(请注意,不再需要注释):

public class MyAttributeConverter implements AttributeConverter<X,Y> {

    private final MySpringBean bean;

    public MyAttributeConverter(MySpringBean bean) {
        this.bean = bean;
    }

    public Y convertToDatabaseColumn(X attribute) {
      ...
    }

    public X convertToEntityAttribute(Y dbData) {
      ...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好的,所以如果您自定义了 JPA 配置(即定义您自己的 `LocalContainerEntityManagerFactoryBean`),这将无法开箱即用,您需要自己配置将 `LocalContainerEntityManagerFactoryBean` 连接到 Spring 的 `BeanFactory` 的 JPA 属性,如下所示根据 [Jürgen Höller 的评论](https://github.com/spring-projects/spring-framework/issues/20852#issuecomment-453465206)。 (2认同)

小智 11

您可以使用静态属性在AttributeConverter中注入bean(@ Component,@ Service,@ Repository)

Setps:

  1. 使用以下注释在AttributeConverter中设置:@ Component,@ Confverter和@Configurable
  2. 使用静态修改器访问权限定义要自动装配的字段
  3. 创建一个init方法以自动装入存储库
  4. 实现AttributeConverter接口中定义的方法

基本上,代码应该看起来像这样......

//Step 1
@Component
@Converter
@Configurable
public class MyAttributeConverter implements AttributeConverter<X,Y> {
    //Where: X = the type of the entity attribute and Y = the type of the database column

    //Step 2
    private static MyRepository myRepository;

    //Step 3
    @Autowired
    public void initMyRepository(MyRepository myRepository){
        MyAttributeConverter.myRepository = myRepository;
    }

    //Step 4
    Y convertToDatabaseColumn(X attribute){//TODO implement method}
    X convertToEntityAttribute(Y dbData){//TODO implement method}
}
Run Code Online (Sandbox Code Playgroud)

我希望它可以帮助!!!


Fen*_*cer 7

一般来说,Ipandzic 的回答是我猜的正确提示。然而,他如何描述它对我不起作用。I argument-constructor 在 Spring 环境中看起来也有点奇怪。我玩了一会儿,并且能够使用以下形式的 AttributeConverter(实际上,您不需要 -类本身的@Converter-annotation 或任何其他AttributeConverter):

import javax.persistence.AttributeConverter;
import org.springframework.beans.factory.annotation.Autowired;

public class MyConverter implements AttributeConverter<String, String> {
    @Autowired
    private MyBean mybean;

    public String convertToDatabaseColumn(String value) {
        return myBean.changeValue(value);
    }

    public String convertToEntityAttribute(String dbValue) {
        return myBean.undoChange(dbValue);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是创建这个类并升级到 Spring-Boot 2.1(包括 Spring 5.1、Hibernate 5.3 和 JPA 2.2)对我来说并没有成功。问题是,我曾经LocalContainerEntityManagerFactoryBean配置我的持久存储,它不会为AttributeConverters启用依赖注入。阅读 Ipandzic 发布的第一个链接表明您必须以LocalSessionFactoryBuilder某种方式发挥作用。这就是为什么我最终得到了以下配置:

//...

@Bean
public LocalSessionFactoryBean entityManagerFactory(DataSource dataSource, Environment env) {
    LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    factory.setDataSource(dataSource);

    // somehow tell the factory where you entitiy-definitions are, this is just
    // one possibility of doing so:
    String entityPackage = JpaMarkerModel.class.getPackage().getName();
    log.info("EntityManager will scan for entities in package [{}].", entityPackage);
    factory.setPackagesToScan(entityPackage);

    return factory;
}

@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}

//...
Run Code Online (Sandbox Code Playgroud)

这个“答案”只是 Ipandzi 的补充,但也许它可以帮助一些人比我更快地解决他们的问题。

  • 我遇到了类似的问题,升级了所有依赖项,但仍然没有自动装配。提到“LocalContainerEntityManagerFactoryBean”是一个线索 - 我们在应用程序上下文/配置中显式创建它,因此使用了非 Spring BeanContainer。Github问题的链接为我提供了答案:`LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean(); emfb.getJpaPropertyMap().put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));` (4认同)