8

我习惯于使用 Spring 来进行依赖注入,如下所示:

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

然后Autowired像这样注释我的依赖类:

public class DependentClass {

    @Autowired
    private Dependency dependency;

}

然而,随着 Hibernate 4.0 的变化,我们现在被建议使用新的Integrator接口来进行服务发现。这包括为触发器添加事件侦听器,例如postUpdatepostDelete

不幸的是,这不能很好地与通过注释依赖项进行的依赖项注入配合使用。我有以下设置:

我定义的集成器将我的侦听器添加到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);

}

我还定义了 class MyListener,它看起来像您的典型事件侦听器。

@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 接口中使用依赖注入的最佳方法是什么?Integrator 用于构建 SessionFactory,因此当他们被要求集成自己时,我想没有可用的应用程序上下文。因此,我在 Integrator 中需要的任何 bean 都需要以“老式”方式创建,并且不会收到它们的自动装配。

我对 Spring 的世界很陌生,你会说这是我应该期待看到的吗?我知道当我在 SessionFactory 中时,我处于应用程序的不同范围内,但是有没有办法获得对 bean 的引用并启用自动装配,即使我是通过创建它的new

我想出的解决方案使用了ApplicationContextAware. 这意味着只要上下文可用,就会MyListener收到ApplicationContext对 bean 的引用,并且我在方法调用而不是 bean 构造时从上下文中引用 bean。创建一个 beannew并没有限制这一点,所以 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-managed beans 的自定义验证器:

<!-- 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 回答