【发布时间】:2013-04-07 20:11:30
【问题描述】:
我习惯于像这样使用 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;
...
}
那么监听器不会自动连接。
首先,在使用 Spring 时不得不做new MyListener() 感觉不对。我希望能够将其定义为自动装配的依赖项,并让 Spring 为我创建一个单例。我的问题是这样的:
在新的 Integrator 接口中使用依赖注入的最佳方法是什么? Integrator 用于构建 SessionFactory,因此当他们被要求集成自己时,我想没有可用的应用程序上下文。因此,我在 Integrator 中需要的任何 bean 都需要以“老式”方式创建,并且不会接收到它们的自动装配。
我对 Spring 的世界还很陌生,你认为这是我应该期待看到的吗?我知道当我在 SessionFactory 中时,我处于应用程序的不同范围内,但是即使我是通过 new 创建它,是否有办法获取对 bean 的引用并启用自动装配?
我想出的解决方案使用了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);
}
}
有没有更好的办法?
【问题讨论】:
-
您没有忘记在您的
@Autowired示例中对MyIntegrator类进行组件扫描?另外,谁在实例化MyIntegrator类? -
这也是我想出的完全相同的解决方案。它工作得很好,但静态应用程序上下文感觉有点脏:)我只是没有找到更好的方法,因为休眠正在创建集成器。一旦我有时间,我想让它更抽象,并拥有一个集成器,它只是一个链接,能够注册由 spring 创建的侦听器等。我曾经找到一个博客,但我现在不记得网址了。
-
@SotiriosDelimanolis Hibernate 为您创建
Integrator。您在META-INF/services目录中指定一个文本文件,指向您想要实例化的集成器列表,Hibernate 在创建 SessionFactory 之前为您构建它们。我有点理解无法在 Integrator 中自动装配组件 - 它是在应用程序范围之外构建的。但是,我认为可以在侦听器中使用@Autowired。是的,我正在对所有涉及的类进行上下文扫描。 -
@MartinFrey 是的,我知道你的意思。我确实考虑过只有一个集成器,但感觉不对。 Hibernate 似乎希望您指定各种集成器来装饰您的
SessionFactory。如果你得到博客链接,请告诉我。 -
我刚刚重新检查了我的实现,我终于走了另一条路。基本上我在我的集成器中自动装配 HibernateEntityManagerFactory 并使用 serviceregistry 来实现我的侦听器。这种方式完全像Spring。我发布我的代码作为答案。
标签: java spring hibernate spring-mvc inversion-of-control