关于SpringBoot的valid校验运行原理-自学

news/2025/4/2 20:54:12/文章来源:https://www.cnblogs.com/zf-crazy/p/18803824
工作的时候突然想到一个问题,valid运行机制。为什么直接引入包就可以了,valid运行机制。为什么直接引入包就可以了??
启动程序的时候:
classLoader.getResources("META-INF/spring.factories") ; //获取所有查看有这个spring.factories文件的引入的jar包
在spring-boot-autoconfigure包里面的配置文件配置了需要启动时调用方法org.springframework.boot.autoconfigure.BackgroundPreinitializer在org.springframework.boot.autoconfigre.BackgroundPreinitializer类 performPreinitialization()当中配置当中//初始化ByteBuffer、字符串时区、时区时间转Calendar、对象之间转换、失败对象转字符串、对象转参数等等...this.runSafely(new ConversionServiceInitializer());//初始化校验模块(在这里...........)this.runSafely(new ValidationInitializer());//初始化消息转换模块 (支持消息转换模型 
            javax.xml.bind.Binder 、 com.fasterxml.jackson.databind.ObjectMapper 、 com.fasterxml.jackson.dataformat.xml.XmlMapper 、 com.fasterxml.jackson.dataformat.smile.SmileFactory 、com.google.gson.Gson、javax.json.bind.Jsonb)this.runSafely(new MessageConverterInitializer());//初始化MBean模块 (涉及tomcat相关模块 StringManager 内置线程安全hashtable;javax.management.MBeanServer) JMX核心this.runSafely(new MBeanFactoryInitializer());this.runSafely(new JacksonInitializer());//初始化字符集 UTF-8this.runSafely(new CharsetInitializer());//计数器-1
        BackgroundPreinitializer.preinitializationComplete.countDown();会预先加载 javax.validation.Validation.java中调用的configure()方法(在validation-api的jar包中)
configrure()内部会在Validation.java中的内部私有单例类调用run方法:
1.获取当前线程的上下文ClassLoader
2.根据ClassLoader获取缓存cachedContextClassLoaderProviderList 列表
3.如果缓存没有,则通过loadProviders()方法进行加载://java公共方法,将实现了javax.validation.spi.ValidationProvider接口的加载到LazyIterator 对象当中java.util.ServiceLoader.load( ValidationProvider.class, classloader )
4.迭代里面找到实现了ValidationProvider接口的实例类 org.hibernate.validator.HibernateValidator
5.通过class.newInstance()进行实例化
6.这里可能会有实现多个ValidationProvider接口的实例类,但是在configrure()内部会在Validation.java 只会取第一个。//自动加载就完成了..
请求调用接口是这样.......1.启动的时候先找org.springframework.context.ApplicationContextInitializer 模块
2.在找org.springframework.context.ApplicationListener 模块
3.在找org.springframework.boot.autoconfigure.AutoConfigurationImportListener 模块
4.在找org.springframework.boot.autoconfigure.AutoConfigurationImportFilter 模块
5.在找org.springframework.boot.autoconfigure.EnableAutoConfiguration 模块1.启动的时候在spring-boot-autoconfigure包里面的配置文件
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext 调用finishBeanFactoryInitialization(beanFactory)方法 创建服务.
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletContext servletContext)
org.springframework.boot.web.servlet.ServletContextInitializerBeans (添加servlet进去)
添加几种模式:
ServletRegistrationBean、
FilterRegistrationBean、
DelegatingFilterProxyRegistrationBean、
ServletListenerRegistrationBean、
或者ServletContextInitializer实现了接口的自定义Bean请求接口的时候:(内部socket连接),建立连接
1.通过org.apache.tomcat.util.net.NioEndpoint 调用org.apache.coyote.AbstractProtocol.process()方法
2.process()内部调用org.apache.coyote.http11.Http11Processor.service()方法,
3.在service()里面进入了适配器(org.apache.catalina.connector.CoyoteAdapter)
4.在service()语法块中,postParseRequest(req, request, res, response);方法内设置了request、response基础信息5.并在之后的this.connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
实际上是到...org.apache.catalina.core.StandardEngineValve.invoke(Request request, Response response)
通过连接得到服务、得到容器、得到管道、取第一个管道,进行回调
6.进一步到 -> org.apache.catalina.valves.ErrorReportValve.invoke(Request request, Response response) (这里处理servlet异常抛出问题)
7.进一步到 -> org.apache.catalina.core.StandardHostValve.invoke(Request request, Response response)
8.进一步到 -> org.apache.catalina.authenticator.AuthenticatorBase.invoke(Request request, Response response)
9.进一步到 -> org.apache.catalina.core.StandardContextValve.invoke(Request request, Response response)
10.进一步到-> org.apache.catalina.core.StandardWrapperValve.invoke(Request request, Response response)在 org.apache.catalina.core.StandardWrapper.allocate() 加载【servlet(DisPatchServlet)】 在 request中设置 :org.apache.catalina.core.DISPATCHER_TYPE 和org.apache.catalina.core.DISPATCHER_REQUEST_PATH 参数通过  StandardWrapper wrapper = (StandardWrapper)this.getContainer(); 得到wrapper10.1.进一步到-> org.apache.catalina.core.ApplicationFilterFactory.createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet)创建filterChain,并通过filterChain.setServlet(servlet) 将servlet 设置到filter里面===============================通过 StandardContext context = (StandardContext)wrapper.getParent();FilterMap[] filterMaps = context.findFilterMaps(); 得到filterMap对象包含:characterEncodingFilter、webMvcMetricsFilter、hiddenHttpMethodFilter、httpPutFormContentFilter、requestContextFilter、org.springframework.boot.actuate.web.trace.servlet.httpTraceFilter、Tomcat WebSocket (JSR356) Filter这些Filter都继承了OncePerRequestFilter================================
遍历filterMap 通过匹配Dispatch类型以及url或者servlet名称的 ,filterConfig
= (ApplicationFilterConfig)context.findFilterConfig(filterMaps[i].getFilterName()); 得到filterConfig对象并依次通过 filterChain.addFilter(filterConfig)加入到加入到filter列表中 11.通过返回的filterChain.doFilter(request.getRequest(), response.getResponse()) 进行filter处理 12.进入org.springframework.web.filter.doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) 处理filter 13.进入org.springframework.web.filter.OncePerRequestFilter.doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)通过抽象函数this.doFilterInternal(httpRequest, httpResponse, filterChain);调用对应的Filter实例方法 13.进入 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 14....依次进入Filter 在httpTraceFilter->org.apache.tomcat.websocket.server.wsFilter之后。。进入servlet处理 15.org.springframework.web.servlet.doDispatch(HttpServletRequest request, HttpServletResponse response)进行分发在方法内调用 mappedHandler.applyPreHandle(processedRequest, response) 获取拦截器列表WebMvcConfig、ConversionServiceExposingInterceptor、ResourceUrlProviderExposingInterceptor16.拦截器过后执行AbstractHandlerMethodAdapter.handler() org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handler(HttpServletRequest request, HttpServletResponse response, Object handler) 17.进入 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)进入 invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) 方法 18.进入org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs)org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs)org.springframework.web.method.support.resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)org.springframework.web.servlet.mvc.method.annotation.resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)执行了this.validateIfApplicable(binder, parameter);会去找注解为@Validated 或者@Valid开头的注解校验(这里就可以自定义校验注解,只要是Valid开头的) 19.进入org.springframework.validation.DataBinder.validate(Object... validationHints) org.springframework.boot.autoconfigure.validation.ValidatorAdapter.validate(Object target, Errors errors, Object... validationHints)org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(@Nullable Object target, Errors errors, @Nullable Object... validationHints)org.hibernate.validator.internal.engine.ValidatorImpl.validate(T object, Class<?>... groups) (实现了接口implements Validator, ExecutableValidator)org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidationContext<T> validationContext, ValueContext<U, Object> valueContext, ValidationOrder validationOrder)org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidationContext<?> validationContext, ValueContext<?, Object> valueContext)org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidationContext<?> validationContext, ValueContext<U, Object> valueContext)org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidationContext<?> validationContext, ValueContext<U, Object> valueContext, Map<Class<?>, Class<?>> validatedInterfaces, Class<? super U> clazz, Set<MetaConstraint<?>> metaConstraints, Group defaultSequenceMember)在这里while(true)遍历所有校验值....org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidationContext<?> validationContext, ValueContext<?, Object> valueContext, Object parent, MetaConstraint<?> metaConstraint)org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(ValidationContext<?> validationContext, ValueContext<?, Object> valueContext)org.hibernate.validator.internal.metadata.core.MetaConstraint.doValidateConstraint(ValidationContext<?> executionContext, ValueContext<?, ?> valueContext)org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ValidationContext<T> executionContext, ValueContext<?, ?> valueContext)org.hibernate.validator.internal.engine.constraintvalidation.SimpleConstraintTree.validateConstraints(ValidationContext<T> validationContext, ValueContext<?, ?> valueContext, Set<ConstraintViolation<T>> constraintViolations)ConstraintValidator<B, ?> validator = this.getInitializedConstraintValidator(validationContext, valueContext); (得到校验器)ConstraintValidatorContextImpl constraintValidatorContext = new ConstraintValidatorContextImpl(validationContext.getParameterNames(), validationContext.getClockProvider(), valueContext.getPropertyPath(), this.descriptor, validationContext.getConstraintValidatorPayload());this.validateSingleConstraint(validationContext, valueContext, constraintValidatorContext, validator)在方法validateSingleConstraint(ValidationContext<T> executionContext, ValueContext<?, ?> valueContext, ConstraintValidatorContextImpl constraintValidatorContext, ConstraintValidator<A, V> validator)里面V validatedValue = valueContext.getCurrentValidatedValue();执行isValid = validator.isValid(validatedValue, constraintValidatorContext);进行校验

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/909455.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

征程 6 系统 power 状态机介绍

1.征程 6X 电源状态 1.1征程 6X 芯片电源域 征程 6x 内部有 AON、MCU 和 Main 域三个电源域。其中 AON 为非下电状态需要一直供电的电源域,MCU 电源域用于给 Hsm 和 MCU 及其内部 IP 供电,Main 域给其他部分供电。 1.2征程 6X 电源状态列表 征程 6x 目前实现了 Off,MCU only…

【Day1】704. Binary Search

Source:Leetcode URL:https://leetcode.cn/problems/binary-search/description/Notes 这道题目考察的是Array的知识,题目要求在nums中寻找sum为target的index,存在返回index,不存在返回-1。All the integers in nums are unique.nums is sorted in ascending order.两条约束…

强化学习理论-第8课-值函数近似

当state space太大的时候,需要用一个函数来对state value 或action value进行近似,方便处理 1. Algorithm for state value estimation 1.1 Objective function这里\(d_{\pi}\)是权重,可以决定哪个state权重比较大,就让它的误差变得更小这里的\(P_{\pi}\)和贝尔曼公式里的是…

K8s污点容忍调度逃逸

污点与容忍 简单说: 污点:被打上污点Taints的节点,不会被调度器部署pod应用。 容忍:允许调度器部署pod应用到打上污点Taints的节点。 污点(Taints) 污点里的值有三种: 1. NoSchedule:POD 不会被调度到标记为 taints 节点。(不会被调度) 2. PreferNoSchedule:NoSchedul…

创建windows脚本bat/cmd或jar为windows服务完整教程

​一、将windows bat/cmd脚本创建为windows服务 1、下载winsw工具 https://gitee.com/colinisg/winsw/releases/download/v2.12.0/WinSW-2.12.0-x64.exe 2、创建服务配置xml文件 ①将下载的工具WinSW-2.12.0-x64.exe放到脚本目录位置,并修改名称,这里的名称是要安装的服务的名…

【每日一题】20250401

四月清和雨乍晴,南山当户转分明。 更无柳絮因风起,惟有葵花向日倾。【每日一题】 1.(5分) \(\hspace{0.7cm}\)在某次光电效应实验中,得到的遏止电压 \(U_c\) 与入射光的频率 \(\nu\) 的关系如图 \(1\) 所示,若该直线的斜率和截距分别为 \(k\) 和 \(b\),电子电荷量的绝对…

字节跳动敏捷实践:2025年OKR与Scrum框架的5大落地经验

随着数字化转型加速,敏捷管理与OKR(目标与关键结果)成为企业提升组织执行力的核心工具。根据《敏捷宣言》提出的价值观,Scrum框架通过固定迭代周期(Sprint)和跨职能协作,帮助团队高效应对需求变化。字节跳动作为全球领先的科技公司,自2016年起将OKR与Scrum深度结合,实…

可视化图解算法: 二叉树的后序遍历

对于二叉树的相关算法,我们总结了一套【可视化+图解】方法,依据此方法来解决相关问题,算法变得易于理解,写出来的代码可读性高也不容易出错。1. 题目 描述 给定一个二叉树,返回他的后序遍历的序列。 后序遍历是值按照 左节点->右节点->根节点 的顺序的遍历。 数据范…

如何估计llm的GPU显存?

如何估计llm的GPU显存?计算本地运行 llm 所需的 GPU 显存随着GPT、 Llama 和 Deepseek等大型 llm 的兴起,人工智能从业者面临的最大挑战之一是弄清楚他们需要多少 GPU 显存来有效地为这些模型服务。GPU 资源昂贵,因此优化显存分配至关重要。这里通过一个简单有效的公式来估…

如何优化和提高MaxKB回答的质量和准确性?

目前 ChatGPT、GLM等生成式人工智能在文本生成、文本到图像生成等在各行各业的都有着广泛的应用,但是由于大模型训练集基本都是构建于网络公开的数据,对于一些实时性的、非公开的或离线的数据是无法获取到的,这个导致了在实际应用场景中会发现,通用的基础大模型基本无法满足…

直线思维的进化:线性到广义线性

在数据科学领域,线性模型和广义线性模型是两种基础且重要的统计工具, 它们被广泛应用于各种预测和分析任务中,从简单的回归问题到复杂的分类场景。 今天,让我们深入探讨这两种模型,了解它们的原理、区别以及实际应用。 1. 线性模型:统计分析的基石 线性模型是统计学中最早…