복붙노트

[SPRING] Hibernate 4의 Integrator 패턴과 Spring의 의존성 주입 사용하기

SPRING

Hibernate 4의 Integrator 패턴과 Spring의 의존성 주입 사용하기

스프링을 사용하여 의존성 주입을하는 데 익숙합니다.

<context:component-scan base-package="org.emmerich.myapp" />

내 종속 클래스에 Autowired로 주석 달기 :

public class DependentClass {

    @Autowired
    private Dependency dependency;

}

그러나 Hibernate 4.0의 변경으로 새로운 Integrator 인터페이스를 서비스 검색에 사용하는 것이 좋습니다. 여기에는 postUpdate, postDelete 등과 같은 트리거에 대한 이벤트 리스너가 추가됩니다.

불행하게도, 이것은 주석이 달린 의존성을 통한 의존성 주입과 잘 일치하지 않습니다. 다음과 같은 설정이 있습니다.

ServiceFactory에 리스너를 추가하기 위해 정의한 통합 자. 이것은 META-INF / services / org.hibernate.integrator.spi.Integrator 파일에서 참조됩니다.

public class MyIntegrator implements Integrator {

    private MyListener listener;

    public MyIntegrator() {
        listener = new MyListener();
    }

    @Override
    public void integrate(Configuration configuration,
                          SessionFactoryImplementor sessionFactory,
                          SessionFactoryServiceRegistry serviceRegistry) {
    final EventListenerRegistry eventRegistry =
        serviceRegistry.getService(EventListenerRegistry.class);

    eventRegistry.prependListeners(EventType.POST_COMMIT_INSERT, listener);

}

또한 일반적인 이벤트 리스너처럼 보이는 MyListener 클래스를 정의했습니다.

@Component
public class MyListener implements PostInsertEventListener {

    @Autowired
    private Dependent dependent;

    public void onPostInsert(PostInsertEvent event) {
         // dependent == null
    }

}

유감스럽게도 댓글에 표시된대로 작동하지 않습니다. MyIntegrator 내부에서 MyListener를 인스턴스화하고 있기 때문에 구성 요소를 선택하지 않고 구성 요소를 자동으로 호출하지 않기 때문입니다. 그러나, 내가 이것을 시도하면 :

@Component
public class MyIntegrator {

     @Autowired
     private MyListener listener;

     ...
}

그러면 리스너는 자동 실행되지 않습니다.

첫째로, 새로운 MyListener ()를해야하기 때문에 Spring을 사용하면서 잘못 생각합니다. autowired 의존성을 정의하고 Spring이 나를 위해 싱글 톤을 생성하도록 기대할 수있을 것으로 기대합니다. 내 질문은 이것이다 :

새로운 Integrator 인터페이스로 종속성 삽입을 사용하는 최선의 방법은 무엇입니까? Integrator는 SessionFactory를 구현하는 데 사용되므로, 스스로 통합 할 것을 요청 받았을 때 사용할 수있는 애플리케이션 컨텍스트가 없다고 생각합니다. 그렇기 때문에 Integrator에서 필요로하는 모든 bean은 "구식"방식으로 작성해야하며 autowiring을받지 못합니다.

나는 봄의 세계에 대해 아주 새로운데, 이것이 내가 볼 것으로 기대해야한다고 말하는가? 나는 SessionFactory에있을 때 응용 프로그램의 다른 범위에 있다는 것을 알지만 bean을 참조하고 autowire를 활성화하는 방법은 새로운 것을 통해 만들지 만?

내가 사용한 ApplicationContextAware를 사용한 해결책. 즉, 컨텍스트를 사용할 수있을 때마다 MyListener가 ApplicationContext에 대한 참조를 받았다는 것을 의미하며 Bean 생성이 아닌 메소드 호출에서 컨텍스트에서 Bean을 참조했습니다. new로 bean을 생성하는 것은 이것을 제한하지 않기 때문에 Spring은 여전히 ​​애플리케이션 컨텍스트를 제공한다.

@Component
public class MyListener implements PostInsertEventListener, ApplicationContextAware {

    private static ApplicationContext context;

    public void onPostInsert(PostInsertEvent event) {
         // getDependent() == correct!
    }

    public void setApplicationContext(ApplicationContext context) throws BeanException {
        this.context = context;
    }

    public Dependent getDependent() {
        return context.getBean(Dependent.class);
    }

}

더 좋은 방법이 있습니까?

해결법

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

    1.의견에서 언급했듯이 Spring에서 관리하는 HibernateEventListeners를 통합하는 다른 방법을 찾아 보았습니다. 코드는 다음과 같습니다.

    의견에서 언급했듯이 Spring에서 관리하는 HibernateEventListeners를 통합하는 다른 방법을 찾아 보았습니다. 코드는 다음과 같습니다.

    Spring에서 관리하는 Hibernate 이벤트 리스너를위한 식별자 인터페이스 :

    public interface HibernateEventListener { }
    

    Hibernate Integrator :

    @Service
    public class HibernateSpringIntegrator {
    
        private static final Logger log = LoggerFactory.getLogger(HibernateSpringIntegrator.class);
    
        @Autowired
        private HibernateEntityManagerFactory entityManagerFactory;
    
        @Autowired
        private HibernateSpringIntegratorRegistry hibernateSpringIntegratorRegistry;
    
        @PostConstruct
        public void registerListeners() {
            log.debug("Registering Spring managed HibernateEventListeners");
    
            EventListenerRegistry listenerRegistry = ((SessionFactoryImpl) entityManagerFactory
                    .getSessionFactory()).getServiceRegistry().getService(
                    EventListenerRegistry.class);
            List<HibernateEventListener> eventListeners = hibernateSpringIntegratorRegistry
                    .getHibernateEventListeners();
            for (HibernateEventListener hel : eventListeners) {
                log.debug("Registering: {}", hel.getClass());
                if (PreInsertEventListener.class.isAssignableFrom(hel.getClass())) {
                    listenerRegistry.appendListeners(EventType.PRE_INSERT,
                            (PreInsertEventListener) hel);
                }
                if (PreUpdateEventListener.class.isAssignableFrom(hel.getClass())) {
                    listenerRegistry.appendListeners(EventType.PRE_UPDATE,
                            (PreUpdateEventListener) hel);
                }
                if (PreDeleteEventListener.class.isAssignableFrom(hel.getClass())) {
                    listenerRegistry.appendListeners(EventType.PRE_DELETE,
                            (PreDeleteEventListener) hel);
                }
                if (PostInsertEventListener.class.isAssignableFrom(hel.getClass())) {
                    listenerRegistry.appendListeners(EventType.POST_INSERT,
                            (PostInsertEventListener) hel);
                }
                if (PostUpdateEventListener.class.isAssignableFrom(hel.getClass())) {
                    listenerRegistry.appendListeners(EventType.POST_UPDATE,
                            (PostUpdateEventListener) hel);
                }
                if (PostDeleteEventListener.class.isAssignableFrom(hel.getClass())) {
                    listenerRegistry.appendListeners(EventType.POST_DELETE,
                            (PostDeleteEventListener) hel);
                }
                // Currently we do not need other types of eventListeners. Else this method needs to be extended.
            }
        }
    }
    

    "레지스트리":

    @Component
    public class HibernateSpringIntegratorRegistry {
    
        @Autowired(required = false)
        private List<HibernateEventListener> hibernateEventListeners;
    
        public List<HibernateEventListener> getHibernateEventListeners() {
            if (hibernateEventListeners == null) {
                return Collections.emptyList();
            }
            return hibernateEventListeners;
        }
    }
    

    다음은 구현 예입니다.

    @Component
    public class MailGenerationEventListener implements HibernateEventListener, 
        PostDeleteEventListener, PostInsertEventListener, PostUpdateEventListener {
    
        @Override
        public void onPostDelete(PostDeleteEvent event) {
            Class<?> entityClass = event.getEntity().getClass();
            ...
        }
    
        @Override
        public void onPostInsert(PostInsertEvent event) {
            Class<?> entityClass = event.getEntity().getClass();
            ...
        }
    
        @Override
        public void onPostUpdate(PostUpdateEvent event) {
            Class<?> entityClass = event.getEntity().getClass();
            ...
        }
    }
    
  2. ==============================

    2.Hibernate 3.6에서 4.2로 업그레이드하는 동안 다음 구성을 수행하여 스프링 관리 빈을 사용하는 사용자 정의 유효성 검사기가 필요했습니다.

    Hibernate 3.6에서 4.2로 업그레이드하는 동안 다음 구성을 수행하여 스프링 관리 빈을 사용하는 사용자 정의 유효성 검사기가 필요했습니다.

    <!-- Make our validators use DI if necessary -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
    
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <!-- other props -->
        <property name="hibernateProperties">
                <map>
                    <entry key="javax.persistence.validation.factory" value-ref="validator" />
                </map>
        </property>
    </bean>
    
  3. from https://stackoverflow.com/questions/16019820/using-hibernate-4s-integrator-pattern-and-springs-dependency-injection by cc-by-sa and MIT license