JSR-303 依赖注入和 Hibernate

     2023-02-26     91

关键词:

【中文标题】JSR-303 依赖注入和 Hibernate【英文标题】:JSR-303 dependency injection and Hibernate 【发布时间】:2011-02-12 07:56:07 【问题描述】:

春季 3.0.2, 休眠 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。稍后当刷新触发 preInsert 时,会创建并调用不同的 ConstraintValidator。问题是 EntityManager 在这个新的 ConstraintValidator 中为空。我尝试在 ConstraintValidator 中注入其他依赖项,这些依赖项始终为空。

有谁知道是否可以将依赖项注入到 ConstraintValidator 中?

【问题讨论】:

【参考方案1】:

在 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"/>

享受吧!

【讨论】:

您可能会觉得这个问题很有趣。我无法在类似的情况下解决问题。 ***.com/questions/13599821/… 使用 Spring 4 + Hibernate 4.3 + HV 5.1。我花了惊人的时间来解决运行系统中存在多个 ValidationFactories 的问题。这工作正常。 @MartinFrey 这里也一样!通过调试hibernate代码找到解决方案后,只需到达此页面。这似乎是一个无证的“秘密”财产......【参考方案2】:

虽然 JSR-303(Hibernate Validator 是参考实现)实例化了我们的自定义 ConstraintValidator,但它实际上将实际创建委托给了 ValidatorFactory。 因此,您认为使用 Spring 的 LocalValidatorFactoryBean 应该为整个应用程序中的自定义验证器启用依赖注入是正确的。

这里的微妙之处在于,在处理实体生命周期事件(更新前、插入前、删除前)时,Hibernate 本身使用了一个单独的 ValidatorFactory,而不是在 Spring 上下文中配置的那个。我认为这是设计使然:Hibernate Validator 不知道 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>

由于我一直在努力寻找如何做到这一点,所以我在这里整理了一个演示应用程序 on Github README 文件是不言自明的。

【讨论】:

不适用于 Hibernate 4、Spring 3.1。新版本无法设置事件监听器属性。我也在尝试基于集成器的方法。 ***.com/a/11672377/161628。但它报告了重复事件侦听器注册错误。【参考方案3】:

似乎在 JPA2 中,持久性提供程序的验证机制默认在 pre-persist、pre-update 等时启动。

它使用自己的机制来构造验证器,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 中拉出,但我没有看到任何干净的方法。

【讨论】:

&lt;validation-mode&gt;NONE&lt;/validation-mode&gt; 可以解决问题。而且您甚至不必手动调用验证器。 Spring 将验证传递给 Hibernate Validator。使用 Hibernate Validator 4.1,我遇到了突然所有实体都被验证两次的问题。一次通过 Spring(自动装配)和一次通过 HV(失败,因为没有自动装配)。不过,它适用于 Hibernate Validator 4.0。 以及将“javax.persistence.validation.mode”设置为“none”。【参考方案4】:

对于 Spring 4.0.5 和 Hibernate 4.3.5,我能够使用 EL 解决这个问题:

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
...
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    ...
    <property name="hibernateProperties">
        <props>
            ...
            <prop key="javax.persistence.validation.factory">#validator</prop>
        </props>
    </property>
</bean>

【讨论】:

【参考方案5】:

还可以选择将 ValidatorFactory 作为属性传递给使用属性 javax.persistence.validation.factory 创建的实体管理器。如果有一个 ValidatorFactory 实例存储在这个属性下,实体管理器使用这个验证器工厂而不是创建一个新的。

【讨论】:

【参考方案6】:

如果您使用的是 Spring Boot 2.1.0+,您可以这样做:

@Configuration
@Lazy
class SpringValidatorConfiguration 


    @Bean
    @Lazy
    public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(final Validator validator) 
        return new HibernatePropertiesCustomizer() 

            @Override
            public void customize(Map<String, Object> hibernateProperties) 
                hibernateProperties.put("javax.persistence.validation.factory", validator);
            
        ;
    

来自Spring Boot 2.0.0 M6 - Add Hibernate Interceptor的想法

和Spring Boot - Hibernate custom constraint doesn't inject Service

【讨论】:

springboot系列jsr-303基于由hibernate-validitor实现的后端服务器数据校验(代码片段)

八、JSR-303基于由Hibernate-Validitor实现的后端服务器数据校验1、JSR-303简介2、JSR-303常用校验注解规则3、JSR-303如何使用?3.1、首先导入相关依赖(**规范**和**实现**)3.2、对实体类SystemUserinfo==部分字段==进行... 查看详情

使用 Hibernate Validator (JSR 303) 进行跨字段验证

】使用HibernateValidator(JSR303)进行跨字段验证【英文标题】:CrossfieldvalidationwithHibernateValidator(JSR303)【发布时间】:2010-12-3016:26:06【问题描述】:HibernateValidator4.x中是否有跨字段验证的实现(或第三方实现)?如果没有,实现跨字... 查看详情

springmvc进行jsr303校验

...的值进行格式化绑定和校验j2ee制定了JSR303标准,这里由hibernate-validator进行实现 一、步骤:1、加入hibernate-validator框架的jar包注意required里面的eljar也是必须的2、配置<mvc:annotation-driven>3、对要校验的bean的字段进行注解,... 查看详情

spring/springbootjsr-303验证框架之hibernate-validator

JSR-303与hibernate-validatorSpring3支持JSR-303验证框架,JSR-303是JavaEE6中的一项子规范,叫做BeanValidation,官方参考实现是hibernate-validator(与HibernateORM没有关系),JSR303用于对JavaBean中的字段的值进 查看详情

jsr303

HibernateValidatorhttp://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html_single/ 查看详情

使用 Spring 3.1.1 配置 Hibernate 4.1、JPA2。从 JSR 303 Annotations 更新数据库模式

】使用Spring3.1.1配置Hibernate4.1、JPA2。从JSR303Annotations更新数据库模式【英文标题】:ConfigureHibernate4.1,JPA2withSpring3.1.1.toupdateDBschemafromJSR303Annotations【发布时间】:2012-03-2323:14:36【问题描述】:在我当前的Hibernate4.1+JPA2+Spring3.1.1配置... 查看详情

spring/springbootjsr-303验证框架之hibernate-validator

JSR-303与hibernate-validatorSpring3支持JSR-303验证框架,JSR-303是JavaEE6中的一项子规范,叫做BeanValidation,官方参考实现是hibernate-validator(与HibernateORM没有关系),JSR303用于对JavaBean中的字段的值进行验证。hibernate-... 查看详情

springmvc的jsr303数据验证(代码片段)

...据验证对于JSR303验证,目前有两个实现,一个是HibernateValicator,另一个是ApacheBVal,本次采用的是HibernateValidator,注意它和Hibernate无关,只是使用它进行数据验证。利用JSR303(Java验证规范)对数据进行验证,验... 查看详情

使用jsr-303进行校验@valid

一、在SringMVC中使用使用注解1、准备校验时使用的JARvalidation-api-1.0.0.GA.jar:JDK的接口;hibernate-validator-4.2.0.Final.jar是对上述接口的实现;log4j、slf4j、slf4j-log4j 2、编写需要校验的bean@NotNull(message="名字不能为空")privateStringuserName 查看详情

使用jsr-303进行后台数据校验

一、在SringMVC中使用使用注解1、准备校验时使用的JARvalidation-api-1.0.0.GA.jar:JDK的接口;hibernate-validator-4.2.0.Final.jar是对上述接口的实现;log4j、slf4j、slf4j-log4j 2、编写需要校验的bean@NotNull(message="名字不能为空")privateStringuserName 查看详情

hibernate-validator校验参数(统一异常处理)

hibernate-validator一、概述BeanValidation源于JSR-303,而JSR303是JavaEE6中的一项子规范。JSR349、JSR380是其升级版,添加了一些新的特性。Oracle公司传统艺能,一流公司定标准,它们只定义了一些校验注解(Constraint),如@Null@NotNull@Pattern]... 查看详情

Spring MVC 和 JSR-303 休眠条件验证

】SpringMVC和JSR-303休眠条件验证【英文标题】:SpringMVCandJSR-303hibernateconditionalvalidation【发布时间】:2011-04-3003:03:56【问题描述】:我有一个要验证的表单。它包含2个地址变量。address1必须始终被验证,address2必须根据某些条件进... 查看详情

springmvc使用jsr-303进行校验@valid

 一、准备校验时使用的JARvalidation-api-1.0.0.GA.jar:JDK的接口;hibernate-validator-4.2.0.Final.jar是对上述接口的实现; 二、编写需要校验的bean1@NotNull(message="名字不能为空")2privateStringuserName;3@Max(value=120,message="年龄最大不能查 查看详情

java示例代码_Spring和JSR303验证。如何只验证某些属性

java示例代码_Spring和JSR303验证。如何只验证某些属性 查看详情

JSF 2 动态表单和 bean 验证 JSR 303

】JSF2动态表单和bean验证JSR303【英文标题】:JSF2dynamicformandbeanvalidationJSR303【发布时间】:2011-10-0101:15:37【问题描述】:我从带注释的bean开始生成一个动态表单。使用HibernateValidator对同一个bean进行注释以进行验证。表单已正确呈... 查看详情

springboot2.3.x-jsr303效验不显示(代码片段)

版本2.3.7.RELEASE导入依赖Spring2.3.x的版本取消了JSR依赖包,需要导入 <dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final&l 查看详情

springboot2.3.x-jsr303效验不显示(代码片段)

版本2.3.7.RELEASE导入依赖Spring2.3.x的版本取消了JSR依赖包,需要导入 <dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final&l 查看详情

JSR 303 Bean 验证 + Javascript 客户端验证

】JSR303Bean验证+Javascript客户端验证【英文标题】:JSR303BeanValidation+JavascriptClient-SideValidation【发布时间】:2011-01-3114:45:09【问题描述】:在服务器端使用JSR303bean验证时,使用Javascript执行客户端表单验证(代码重复最少)的最佳方... 查看详情