8

私は、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また、典型的なイベント リスナーのように見えるclass も定義しました。

@Component
public class MyListener implements PostInsertEventListener {

    @Autowired
    private Dependent dependent;

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

}

残念ながら、コメントで示されているように、これは機能しません。MyListener内部でインスタンス化しているためだと思いますがMyIntegrator、コンポーネントを取得せず、コンポーネントを自動配線しません。ただし、これを試してみると:

@Component
public class MyIntegrator {

     @Autowired
     private MyListener listener;

     ...
}

次に、リスナーは自動配線されません。

まず、Spring を使用してやらなければならないことが間違っていると感じますnew MyListener()。それを自動配線された依存関係として定義し、Spring にシングルトンを作成してもらうことができると期待しています。私の質問はこれです:

新しい Integrator インターフェイスで依存性注入を使用する最善の方法は何ですか? インテグレーターは SessionFactory を構築するために使用されるため、インテグレーターが自分自身を統合するように求められたとき、利用可能なアプリケーション コンテキストがないと思います。そのため、インテグレーターで必要な Bean はすべて「昔ながらの」方法で作成する必要があり、自動配線を受け取りません。

私は春の世界にまったく慣れていませんが、これは私が見るべきものだと思いますか? SessionFactory にいるときはアプリケーションの別のスコープにいることは理解していますが、Bean への参照を取得して autowire を有効にする方法はありnewますか?

私が思いついた解決策は、ApplicationContextAware. MyListenerこれは、コンテキストが使用可能なときはいつでもへの参照を受け取ることを意味しApplicationContext、Bean の構築ではなく、メソッド呼び出しでコンテキストから Bean を参照しました。Bean を作成してnewもこれは制限されないため、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);
    }

}

より良い方法はありますか?

4

2 に答える 2

14

コメントで述べたように、Spring が管理する HibernateEventListeners を統合する別の方法に行きました。コードは次のとおりです。

Spring 管理の Hibernate イベントリスナーの識別子インターフェース:

public interface HibernateEventListener { }

HibernateIntegrator:

@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();
        ...
    }
}
于 2013-04-16T19:17:02.877 に答える
-1

hibernate 3.6 から 4.2 へのアップグレード中に、次の構成を行うことで、Spring 管理の Bean を使用するカスタム バリデーターが必要になりました。

<!-- 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>
于 2014-03-17T17:42:26.493 に答える