303依赖注入和Hibernate
Spring 3.0.2,Hibernate 3.5.0,Hibernate-Validator 4.0.2.GA
我正在尝试使用以下方法将Spring依赖注入到ConstraintValidator中:
@PersistenceContext
private EntityManager entityManager;
我已经配置了应用程序上下文:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
根据Spring文档,它应该允许“自定义ConstraintValidators像任何其他Spring bean一样受益于依赖注入”
在调试器中,我可以看到Spring调用getBean来创建ConstraintValidator。 稍后当flush触发preInsert时,会创建并调用不同的ConstraintValidator。 问题是这个新的ConstraintValidator中的EntityManager是null。 我已经尝试在ConstraintValidator内注入其他依赖项,并且这些始终为空。
有谁知道是否有可能向ConstraintValidator注入依赖关系?
在EntityManager中注入Spring上下文的ValidatorFactory的最好方法是使用javax.persistence.validation.factory属性。 配置如下:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="javax.persistence.validation.factory" value-ref="validator" />
</map>
</property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
请享用!
虽然JSR-303(Hibernate Validator是参考实现)实例化了我们的自定义ConstraintValidator,但它实际上将实际创建委托给ValidatorFactory。 所以你认为使用Spring的LocalValidatorFactoryBean应该在整个应用程序中为你的自定义验证器启用依赖注入是正确的。
这里的微妙之处在于,Hibernate本身在处理实体生命周期事件(更新前,预插入,预先删除)时使用了独立的ValidatorFactory,而不是Spring上下文中配置的ValidatorFactory。 这是设计我认为:Hibernate验证器不知道Spring,所以我们必须告诉Hibernate使用Spring的LocalValidatorFactoryBean而不是创建它自己的。
基本上,在你的Spring应用程序上下文XML中需要这样的东西:
<!-- The LocalValidatorFactoryBean is able to instantiate custom validators and inject autowired dependencies. -->
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<!--
This is the key to link Spring's injection to Hibernate event-based validation.
Notice the first constructor argument, this is our Spring ValidatorFactory instance.
-->
<bean id="beanValidationEventListener" class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener">
<constructor-arg ref="validator"/>
<constructor-arg ref="hibernateProperties"/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
...
<!--
A reference to our custom BeanValidationEventListener instance is pushed for all events.
This can of course be customized if you only need a specific event to trigger validations.
-->
<property name="eventListeners">
<map>
<entry key="pre-update" value-ref="beanValidationEventListener"/>
<entry key="pre-insert" value-ref="beanValidationEventListener"/>
<entry key="pre-delete" value-ref="beanValidationEventListener"/>
</map>
</property>
</bean>
由于我一直在努力研究如何去做,所以我在Github上放了一个演示应用程序README文件是不言自明的。
看起来,在JPA2中,持久化提供者的验证机制默认情况下在预留持久性,更新前等情况下进行。
它使用自己的机制来构造验证器,Spring不参与。
我目前唯一能看到的解决方案是禁用persistence.xml中的开箱即用JPA2验证:
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.show_sql" value="true"/>
<!-- other props -->
</properties>
<validation-mode>NONE</validation-mode>
</persistence-unit>
然后照常使用Spring的LocalValidatiorFactoryBean。 然后您必须像JPA2之前的版本那样手动调用验证器。
更新:
为了使其完整,另一个解决方案是在META-INF / validation.xml中指定一个constraint-validator-factory
。
如果这可能是Spring的SpringConstraintValidatorFactory
,那将是非常好的,但不幸的是,它需要将AutowireCapableBeanFactory
传递到它的构造函数中,但JPA2期望有一个没有参数构造函数的类。
这留下了创建自己的实现ConstraintValidatorFactory
的选项,将验证器从Spring中抽出,但我没有看到任何干净的方式。
上一篇: 303 dependency injection and Hibernate
下一篇: Service discovery failed exception using Bluetooth on Android