복붙노트

[SPRING] AttributeConverter 클래스 내의 Spring 빈에 접근하기

SPRING

AttributeConverter 클래스 내의 Spring 빈에 접근하기

나는 스프링 데이터 JPA 애플리케이션을 개발하고 있으며, 객체의 ArrayList를 JSON으로 데이터베이스 컬럼에 저장하기 위해 AttributeConverter 클래스를 만들었다. 이 클래스 안에서 나는 스프링 빈으로 정의한 클래스를 사용할 필요가있다.

AttributeConverter 클래스는 Hibernate에 의해 관리되기 때문에, Spring Bean이 생성되기 전에 인스턴스화 된 것처럼 보이므로 DI가 작동하지 않는 것처럼 보입니다 (AttributeConverter 클래스의 Spring Bean이 null이고 NullPointer 예외가 발생합니다) . 그래서 지금은 콩의 다른 인스턴스를 만들어서 AttributeConverter 클래스에서 사용할 수 있습니다 (이는 DI의 목적을 상실합니다).

또한 SpringBean (cxt.getBean (BeanClass.class))을 제공하는 메소드를 제공하는 ApplicationContextAware를 구현하는 Util 클래스 (@Component로 주석 처리됨)를 작성하려고 시도했습니다. 그러나 이것도 AttributeConverter 후에 인스턴스화됩니다.

이것이 어떻게 풀릴 수 있는지에 대한 생각이 있습니까?

고맙습니다.

해결법

  1. ==============================

    1.정적 속성을 사용하여 AttributeConverter 안에 bean (@Component, @Service, @Repository)을 삽입 할 수 있습니다.

    정적 속성을 사용하여 AttributeConverter 안에 bean (@Component, @Service, @Repository)을 삽입 할 수 있습니다.

    Setps :

    기본적으로 코드는 다음과 같아야합니다.

    //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}
    }
    

    나는 그것이 도울 수 있기를 바란다! !!

  2. ==============================

    2.JPA 2.2, Spring 5.1 ( SPR-16305)와 Hibernate 5.3.0 (HHH-12135)을 사용하면 더 이상 변경 가능한 정적 속성 해킹을 사용할 필요가 없으며 일반 스프링 관리 빈과 마찬가지로 의존성 주입을 사용할 수있다 (주석은 더 이상 필요하지 않음).

    JPA 2.2, Spring 5.1 ( SPR-16305)와 Hibernate 5.3.0 (HHH-12135)을 사용하면 더 이상 변경 가능한 정적 속성 해킹을 사용할 필요가 없으며 일반 스프링 관리 빈과 마찬가지로 의존성 주입을 사용할 수있다 (주석은 더 이상 필요하지 않음).

    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) {
          ...
        }
    }
    
  3. ==============================

    3.일반적으로 Ipandzic의 대답은 내가 생각하기에 올바른 힌트입니다. 그러나 그것은 그가 그것을 묘사 한 방법을 위해 나를 위해 작동하지 않았다. 인자 - 생성자는 Spring 환경에서 약간 이상하게 보입니다. 나는 조금 놀았고 다음과 같은 형태의 AttributeConverter를 사용할 수 있었다. 실제로 (당신은 @ Converter-annotation이나 AttributeConverter 클래스 자체에 다른 것을 필요로하지 않는다.)

    일반적으로 Ipandzic의 대답은 내가 생각하기에 올바른 힌트입니다. 그러나 그것은 그가 그것을 묘사 한 방법을 위해 나를 위해 작동하지 않았다. 인자 - 생성자는 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);
        }
    }
    

    그러나이 클래스를 만들고 Spring-Boot 2.1 (Spring 5.1, Hibernate 5.3, JPA 2.2 포함)으로 업그레이드하는 것은 나에게 도움이되지 못했다. 사실, LocalContainerEntityManagerFactoryBean을 사용하여 AttributeConverters에 대한 Dependency Injection을 사용할 수없는 영구 저장소를 구성했습니다. 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;
    }
    
    //...
    

    이 "대답"은 단지 아이 판 디어 (Ipandzi 's)에 추가 된 것일 뿐이지 만 어쩌면 사람들이 내가했던 것보다 더 빨리 문제를 풀 수 있도록 도와줍니다.

  4. from https://stackoverflow.com/questions/47219421/accessing-spring-beans-inside-attributeconverter-class by cc-by-sa and MIT license