Spring @Validated 失效分析

这篇具有很好参考价值的文章主要介绍了Spring @Validated 失效分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最近在落地 DDD,希望对 command 进行参数校验,由于部分流量入口是 MQ,所以希望在应用层是用 @Validated 进行参数校验,结果。。。

Controller 中使用 @Validated

@Validated 注解的作用这里就不多做介绍了,具体用法在网上应该有不少。

在之前使用 MVC 架构编码时,通常是将 @Validated 注解或者 @Valid 配置在 Controller 的方法中,如下代码所示:

@PostMapping("common/set")
public Response<?> setCommonSetting(@RequestBody @Validated SetCommonSettingReqVO reqVO) {
    //doSomeThings
    return Response.success();
}
复制代码

所以在配置应用层校验时,就想当然的按照类似的写法:

public void addClueTrack(@Validated AddClueTrackCommand command) {
    //doSomeThings
}
复制代码

结果可想而知,@Validated 注解并不生效。

@Validated 是怎么生效的?

竟然不生效,那么就开始分析原因。

首先可以很容易想到,竟然能在方法执行前就拦截进行校验,那么大概率是使用动态代理。就和 @Transactional 事务注解一样,底层都是基于 AOP 实现动态代理。

接下来为了印证这个想法,就是需要深入看看 Spring 实现的。通过 IDE 可以很方便看到有哪些地方引用了 @Validated 注解:

@validated不起作用,spring,java,后端

其中一个类名一下就引起了我的注意 MethodValidationPostProcessor,熟悉 Spring 的小伙伴应该知道,Spring 中有很多 BeanPostProcessor 用于扩展 Bean,Aop 便是基于此实现动态代理的。点进去一看,果不其然:

public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
        implements InitializingBean {

    private Class<? extends Annotation> validatedAnnotationType = Validated.class;

    @Nullable
    private Validator validator;

    //...

    @Override
    public void afterPropertiesSet() {
        //创建切点
        Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
        this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
    }

    protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
        //创建拦截器
        return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
    }
}

public class AnnotationMatchingPointcut implements Pointcut {

    private final ClassFilter classFilter;
    private final MethodMatcher methodMatcher;
    
    public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, boolean checkInherited) {
        //切点只针对类级别
        this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited);
        this.methodMatcher = MethodMatcher.TRUE;
    }

    //...
}
复制代码

MethodValidationPostProcessor 中创建了一个切点,过滤类上添加了 @Validated 的 Bean,只要满足此条件,就会根据 MethodValidationInterceptor 生成对应的代理类。嗯,和 @Transactional 的实现原理差不多。

ok,看到这里我就在应用服务实现上添加了 @Validated 注解,那么此时注解生效了吗?哈哈,进度条还没过半呢😂

理论上类上加上 @Validated 注解,应该会生成动态代理类的,竟然没成功进行参数校验,我能想到的原因有二:

1. MethodValidationPostProcessor 没注入到 BeanFactory 中,所以没生成对应的代理类 2. MethodValidationInterceptor 对还有其他需要满足的条件,而目前还未满足

这里先剧透一下,答案是 2 🌝

MethodValidationInterceptor 需要满足什么条件

竟然答案是2,那这里就先讲一下 MethodValidationInterceptor,MethodValidationPostProcessor 是怎么注册到容器的咱们后面再来讲。

ExecutableValidatorpublic class MethodValidationInterceptor implements MethodInterceptor {

    private final Validator validator;

    @Override
    @Nullable
    public Object invoke(MethodInvocation invocation) throws Throwable {

        // Standard Bean Validation 1.1 API
        ExecutableValidator execVal = this.validator.forExecutables();
        Method methodToValidate = invocation.getMethod();
        Set<ConstraintViolation<Object>> result;

        //获取类本身的实例(非代理类),请记住这里,这里就是和 Controller 最大的区别
        Object target = invocation.getThis();
        Assert.state(target != null, "Target must not be null");

        try {
            //执行参数校验,校验的是当前类,也就是说校验的是 Bean 对应的类
            result = execVal.validateParameters(target, methodToValidate, invocation.getArguments(), groups);
        }
        catch (IllegalArgumentException ex) {
            //doSomeThings
        }
        if (!result.isEmpty()) {
            throw new ConstraintViolationException(result);
        }
        //执行方法
        Object returnValue = invocation.proceed();
        //校验返回值
        result = execVal.validateReturnValue(target, methodToValidate, returnValue, groups);
        if (!result.isEmpty()) {
            throw new ConstraintViolationException(result);
        }

        return returnValue;
    }

}
复制代码

接下来就要看看 ExecutableValidator.validateParameters 这个方法是如何实现的,为了方便阅读,这里我只保留了部分核心代码。根据包名我们大概也能猜到 ExecutableValidator.validateParameters 是 hibernate-validator 包提供的方法,而 @Validated 注解是由 Spring 提供的,所以不生效也就正常了。接下来我们继续往下走,我这里只贴部分核心的代码,中间的栈路径可以根据以下这个路径往下走:

/**
 *  --> org.hibernate.validator.internal.engine.ValidatorImpl#validateParameters  
 *  --> org.hibernate.validator.internal.metadata.BeanMetaDataManager#getBeanMetaData
 *  --> org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl#createBeanMetaData
 *  --> org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl#getBeanConfigurationForHierarchy
 *  --> org.hibernate.validator.internal.metadata.provider.MetaDataProvider#getBeanConfiguration
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#retrieveBeanConfiguration
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#getFieldMetaData
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#findPropertyMetaData
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#findConstraints
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#findCascadingMetaData
 *  <-- ...
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#getMethodMetaData
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#getConstructorMetaData
 *  --> org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider#getClassLevelConstraints
 *  <-- ...
 *  --> org.hibernate.validator.internal.metadata.aggregated.BeanMetaData#hasConstraints
 *  --> org.hibernate.validator.internal.engine.ValidatorImpl#validateParametersInContext
 * 
 */
public class ValidatorImpl implements Validator, ExecutableValidator {
    @Override
    public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
        Contracts.assertNotNull( beanType, MESSAGES.beanTypeCannotBeNull() );
        sanityCheckPropertyPath( propertyName );
        sanityCheckGroups( groups );

        //获取 bean 及其父类、超类的
        BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData( beanType );

        //判断该 bean 是否有约束
        if ( !rootBeanMetaData.hasConstraints() ) {
            return Collections.emptySet();
        }

        PathImpl propertyPath = PathImpl.createPathFromString( propertyName );
        BaseBeanValidationContext<T> validationContext = getValidationContextBuilder().forValidateValue( beanType, rootBeanMetaData, propertyPath );

        ValidationOrder validationOrder = determineGroupValidationOrder( groups );

        //校验参数
        return validateValueInContext(validationContext, value, propertyPath, validationOrder);
    }
    //...
}

复制代码

当我调试到 rootBeanMetaData.hasConstraints() 时,判断没有约束,然后就直接返回了没有进行参数校验。我就想说看看是如何判断 Bean 是否有约束的,于是就返回上层进入 beanMetaDataManager.getBeanMetaData 中看,结果发现里面的代码有够复杂的🌚

public class AnnotationMetaDataProvider implements MetaDataProvider {
  
    //获取类上所有的约束条件
    private <T> BeanConfiguration<T> retrieveBeanConfiguration(Class<T> beanClass) {
        //获取字段上的约束条件
        Set<ConstrainedElement> constrainedElements = getFieldMetaData( beanClass );
        //获取方法上的约束条件(包括参数、返回值)
        constrainedElements.addAll( getMethodMetaData( beanClass ) );
        //获取构造函数
        constrainedElements.addAll( getConstructorMetaData( beanClass ) );
        //获取类上的约束条件
        Set<MetaConstraint<?>> classLevelConstraints = getClassLevelConstraints( beanClass );
        if ( !classLevelConstraints.isEmpty() ) {
            ConstrainedType classLevelMetaData =
                new ConstrainedType(ConfigurationSource.ANNOTATION, beanClass, classLevelConstraints);
            constrainedElements.add( classLevelMetaData );
        }

        return new BeanConfiguration<>(ConfigurationSource.ANNOTATION, beanClass, constrainedElements, getDefaultGroupSequence( beanClass ), getDefaultGroupSequenceProvider( beanClass ));
    }
	
  //查找约束注解
    protected <A extends Annotation> List<ConstraintDescriptorImpl<?>> findConstraintAnnotations(Constrainable constrainable, A annotation, ConstraintLocationKind type) {

      //如果包含 "jdk.internal" and "java" 下的注解,则直接不进行校验
          if ( constraintCreationContext.getConstraintHelper().isJdkAnnotation( annotation.annotationType() ) ) {
          return Collections.emptyList();
      }
      
      List<Annotation> constraints = newArrayList();
      Class<? extends Annotation> annotationType = annotation.annotationType();
      //判断是否有约束条件,也就我们经常配置的 @NotNull,@Min 这类注解
      if ( constraintCreationContext.getConstraintHelper().isConstraintAnnotation( annotationType ) ) {
          constraints.add( annotation );
      }
      //这个没用过,暂时跳过
      else if ( constraintCreationContext.getConstraintHelper().isMultiValueConstraint( annotationType ) ) {
          constraints.addAll( constraintCreationContext.getConstraintHelper().getConstraintsFromMultiValueConstraint( annotation ) );
      }

      return constraints.stream()
          .map( c -> buildConstraintDescriptor( constrainable, c, type ) )
          .collect( Collectors.toList() );
    }
	
    //构建级联元数据构造器,也就是我们常用的 @Valid,在 Bean 中如果我们要对对象属性进行校验,
    //需要在该属性上添加 @Valid,此处便是如此
    private CascadingMetaDataBuilder getCascadingMetaData(JavaBeanAnnotatedElement annotatedElement, Map<TypeVariable<?>, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData) {
        return CascadingMetaDataBuilder.annotatedObject( annotatedElement.getType(), annotatedElement.isAnnotationPresent( Valid.class ),
            containerElementTypesCascadingMetaData, getGroupConversions( annotatedElement.getAnnotatedType() ) );
    }
}


复制代码

顺着上面的栈路径一直往下走,最终发现最核心的几个方法是 getFieldMetaDatagetMethodMetaDatagetConstructorMetaDatagetClassLevelConstraints,这个几方法都是用于获取约束和级联元数据。那么里面到底是怎么获取约束元数据的呢,咱继续往里钻,可以看到最终调用了 findConstraintAnnotations 获取约束元数据,也就是我们平时用到的 @NotNull,@Min 等注解,通过 getCascadingMetaData 获取级联元数据,也就是 @Valid 注解。看到这,是不是很容易就能想到,知道我加上 @Valid 就能成功校验了呢?

于是我尝试了一波,果然没问题。嗯~ 长见识了😂。由于时间有限,ValidatorImpl.validateParametersInContext() 方法我就没有深入进去看了。感兴趣的小伙伴可以自行去看看!!🌝

那么 Controller 为啥直接添加 @Validated 或者 @Valid 就可以呢?

明白了在应用服务实现,准确的说应该是普通 Bean 中应该怎么配置之 @Validated 和 @Valid 使其生效之后,我就很好奇为啥 Controller 只需要单独在方法上配置 @Validated 或者 @Valid 就能成功校验呢?

还记得上面通过 IDE 查看应用 @Validated 注解的类时,我们发现了 MethodValidationPostProcessor,还有另外几个类一看就很像 Controller 参数解析相关的类:

@validated不起作用,spring,java,后端

我在这几个类上各打了一个断点,最终进入的是 AbstractMessageConverterMethodArgumentResolver。

ok,那就看看他是怎么实现的,这里只贴了很参数校验相关的方法:

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {

    protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
        Annotation[] annotations = parameter.getParameterAnnotations();
        for (Annotation ann : annotations) {
            //获取分组信息
            Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
            if (validationHints != null) {
                //进行校验
                binder.validate(validationHints);
                break;
            }
        }
    }
}

public abstract class ValidationAnnotationUtils {
    @Nullable
    public static Object[] determineValidationHints(Annotation ann) {
        Class<? extends Annotation> annotationType = ann.annotationType();
        String annotationName = annotationType.getName();
        //如果是 @valid 注解直接返回一个空数组
        if ("javax.validation.Valid".equals(annotationName)) {
            return EMPTY_OBJECT_ARRAY;
        }
        //如果是 @validated 则返回其分组信息
        Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
        if (validatedAnn != null) {
            Object hints = validatedAnn.value();
            return convertValidationHints(hints);
        }
        if (annotationType.getSimpleName().startsWith("Valid")) {
            Object hints = AnnotationUtils.getValue(ann);
            return convertValidationHints(hints);
        }
        return null;
    }
}

public class DataBinder implements PropertyEditorRegistry, TypeConverter {
    public void validate(Object... validationHints) {
        //此处是关键所在,这里获取的是参数!!!和普通的 Bean 获取到的却是 Bean 本身
        Object target = getTarget();
        Assert.state(target != null, "No target to validate");
        BindingResult bindingResult = getBindingResult();
        // Call each validator with the same binding result
        for (Validator validator : getValidators()) {
            if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
                ((SmartValidator) validator).validate(target, bindingResult, validationHints);
            }
            else if (validator != null) {
                validator.validate(target, bindingResult);
            }
        }
    }
}
复制代码

可以看到,对于 Controller 不论是直接在参数上加上 @Validated 或者 @Valid 注解,都会进入到校验方法,而且校验的就是参数!!!而 Bean 校验的却是 Bean 本身!!!

MethodValidationPostProcessor 和 AbstractMessageConverterMethodArgumentResolver 是怎么被注册到 BeanFactory 的?

明白了 @Validated 的拦截实现的原理后,那么就只剩最后一个问题了,MethodValidationPostProcessor 和 AbstractMessageConverterMethodArgumentResolver 是怎么被注册到 BeanFactory 的。

其实不用看源码大概有也能猜到是 Spring Boot 自动装配的。为了印证一下,我还是贴一下源码:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import(PrimaryDefaultValidatorPostProcessor.class)
public class ValidationAutoConfiguration {

    //...
  
    @Bean
    @ConditionalOnMissingBean
    public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment, @Lazy Validator validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {
        FilteredMethodValidationPostProcessor processor = new FilteredMethodValidationPostProcessor(excludeFilters.orderedStream());
        boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
        processor.setProxyTargetClass(proxyTargetClass);
        processor.setValidator(validator);
        return processor;
    }
}
复制代码

另外就是 AbstractMessageConverterMethodArgumentResolver 的几个实现类,均由 RequestMappingHandlerAdapter 实例化,而 RequestMappingHandlerAdapter 大家知道有 WebMvcAutoConfiguration 自动装配,时间原因,这就不看了。

@validated不起作用,spring,java,后端

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean {
    private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);

        // Annotation-based argument resolution
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
        resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
        resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        resolvers.add(new RequestAttributeMethodArgumentResolver());
	
        // Type-based argument resolution
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());
        resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
        resolvers.add(new ModelMethodProcessor());
        resolvers.add(new MapMethodProcessor());
        resolvers.add(new ErrorsMethodArgumentResolver());
        resolvers.add(new SessionStatusMethodArgumentResolver());
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
        if (KotlinDetector.isKotlinPresent()) {
            resolvers.add(new ContinuationHandlerMethodArgumentResolver());
        }
	
        // Custom arguments
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }
	
        // Catch-all
        resolvers.add(new PrincipalMethodArgumentResolver());
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
        resolvers.add(new ServletModelAttributeMethodProcessor(true));
	
        return resolvers;
    }
}
复制代码

小结

1、在普通 Bean 中如果要通过注解的方式使用 hibernate-validator 进行校验的话,需要在类上添加 @Validated 注解,同时在方法上添加 @Valid 注解。或者也可以直接使用 @NotNull 等注解。

2、普通 Bean 使用 @Validated 是通过动态代理完成的。具体的拦截器便是他 MethodValidationInterceptor。

3、Controller 层之所以能 @Validated 和 @Valid 二选一,是因为校验的是参数本身,而普通 Bean 校验的是 Bean 本身。

4、至此,相信大家就不会没配置好 @Validated 导致失效了。文章来源地址https://www.toymoban.com/news/detail-769288.html

到了这里,关于Spring @Validated 失效分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vscode切换行注释快捷键“ctrl+/“失效、不起作用的处理办法

    今天在使用\\\"ctrl+/\\\"行注释快捷键的时候失效,不起作用,于是去vscode的键盘快捷方式里查找是否有按键冲突,结果在录制按键的时候始终打不出\\\"ctrl+/\\\",只能打出\\\"Ctrl\\\"(见下图) 这代表不是vscode内部导致的快捷键冲突,而是其他软件的快捷键冲突,最后发现是输入法的快捷键冲突

    2024年02月05日
    浏览(34)
  • 揭秘Spring事务失效场景分析与解决方案

    在Spring框架中,事务管理是一个核心功能,然而有时候会遇到事务失效的情况,这可能导致数据一致性问题。本文将深入探讨一些Spring事务失效的常见场景,并提供详细的例子以及解决方案。 场景: 当一个事务方法内部调用另一个方法,而被调用的方法没有声明为 @Transact

    2024年02月02日
    浏览(34)
  • spring-transaction源码分析(3)Transactional事务失效原因

    在Transactional方法中使用this方式调用另一个Transactional方法时,拦截器无法拦截到被调用方法,严重时会使事务失效。 类似以下代码: 正常情况下,执行到\\\"继续插入数据\\\"时会抛出一个\\\"rollback only\\\"的异常,然后事务回滚。 而现在的现象是: 三个操作都不会开启事务,出现异常

    2024年02月03日
    浏览(35)
  • @Valid、@Validated参数校验详解

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M6CfNsNC-1687851467867)(images/20200913110853722.png)] 说明:若不做异常处理,@Validated注解的默认异常消息如下(示例): 因此我们在这里做了一个全局的异常处理类,用于处理参数校验失败后抛出的异常,同

    2024年02月11日
    浏览(29)
  • SpringBoot参数校验@Validated、@Valid

    在实际开发中,前端校验并不安全,任何人都可以通过接口来调用我们的服务,就算加了一层token的校验,有心人总会转空子,来传各式各样错误的参数,如果后端不校验,导致数据库数据混乱、特别是关于金额的数据,可能一个接口把公司都给干倒了 0、返回类(可以不用看

    2024年01月23日
    浏览(33)
  • 【优雅的参数验证@Validated】@Validated参数校验的使用及注解详解——你还在用if做条件验证?

    请先看看下面代码:(简单举个例子,代码并不规范) 以上代码主要是为了对用户user实体进行条件验证。 但是那么多的if, 写得纯纯得小白一个,也使得代码显得臃肿不美观不优雅! 接下来,让我们学习使用优雅的参数验证@Validated! @Valid和@Validated是Spring Validation框架提供

    2024年02月02日
    浏览(30)
  • Springboot @Validated注解详细说明

    在Spring Boot中,@Validated注解用于验证请求参数。它可以应用在Controller类或方法上 1、引入依赖 2、参数说明与使用示例 注解 验证的数据类型 描述 @NotNull 任意类型 验证属性不能为null @NotBlank 字符串 验证字符串属性不能为空且长度必须大于0 @Size(min,max ) CharSequence Collection Map

    2024年02月14日
    浏览(31)
  • @Validated注解不生效问题汇总

    项目框架应用的是validation进行检验的,但是最近一直不生效,然后排查了下问题,总结了失效的常见几个原因: 原因1: 在2.3.0版本之前spring-boot-starter-web是集成了validation检验的 但是在2.3.0开始就去掉了该依赖,所以需要自己添加该依赖。 添加依赖为: 原因2: 参数如果是非

    2024年02月16日
    浏览(33)
  • @Validated注解不生效问题汇总大全

    项目框架应用的是validation进行检验的,但是最近一直不生效,然后排查了下问题,总结了失效的常见几个原因: 在2.3.0版本之前spring-boot-starter-web是集成了validation检验的 但是在2.3.0开始就去掉了该依赖,所以需要自己添加该依赖, 添加依赖为: 下面截图对照下: 2.7.2版本

    2024年02月11日
    浏览(31)
  • 【Spring】Bean的作用域与生命周期详情:请简述Spring的执行流程并分析Bean的生命周期?

     我们都知道,Spring框架为开发人员提供了很多便捷,这使得开发人员能够更加专注于应用程序的核心业务逻辑,而不需要花费大量时间和精力在技术细节上。作为一个包含众多工具方法的IoC容器,存取JavaBean是其极为重要的一个环节。本文就对Spring中的Bean的作用域和生命周

    2024年02月12日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包