初探spring validate

前言

最近在做一個(gè)spring secutiry的項(xiàng)目,是想通過role來控制訪問。但是在調(diào)試的過程中一直沒有進(jìn)入權(quán)限控制代碼,所以進(jìn)行了一個(gè)debug。發(fā)現(xiàn)控制器邏輯先進(jìn)入了validate的代碼,個(gè)人覺得validate應(yīng)在在權(quán)限校驗(yàn)之后處理。遂開始了這次初探體驗(yàn)。

旅程

  1. 剛開始,我認(rèn)為這個(gè)validate是配置在filter或interscepor中的,進(jìn)行了一層debug,最后發(fā)現(xiàn)實(shí)際是在解析參數(shù)的時(shí)候的一個(gè)默認(rèn)操作,具體是在org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgumentz中的resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); 中處理的。具體如圖:
    validere代碼入口

    這里在緩存中尋找resolver來處理后續(xù)的操作。

P.S. 擴(kuò)展一下,具體的resolver可以看org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter

  1. 這里使用org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor來繼續(xù)下面的說明。
    進(jìn)入方法以后,熟悉的converter也出現(xiàn)了,Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());這個(gè)將parameter轉(zhuǎn)換成具體的object。
    后面就是最關(guān)鍵的獲取WebDataBinder,然后進(jìn)行校驗(yàn)了validateIfApplicable(binder, parameter);
    校驗(yàn)

最后回從binder中的result中獲取error來拋出異常,給springmvc的異常處理器來處理。

  1. 到這里開始校驗(yàn)的初判斷,注意看,這里可以支持Valid開頭的注解(包括JSR303種的 @javax.validation.Valid)、org.springframework.validation.annotation.Validated

    image.png

    如果滿足上述的注解要求,那么就開始進(jìn)行校驗(yàn)了。

  2. 具體的binder是org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder,委托給Validator來做校驗(yàn),這里使用了一個(gè)適配器,預(yù)先將javax.validation.ValidatorSpringValidatorAdapter包裝成ValidatorAdapter,擴(kuò)展了org.springframework.validation.Validator的一些功能,支持傳遞一些中間數(shù)據(jù)。當(dāng)然本次運(yùn)行時(shí)使用的是SpringValidatorAdapter

    獲取具體Validator進(jìn)行校驗(yàn)

  3. 再往下探究,我們熟悉的hibernate validator就出現(xiàn)了。原來依然被包裝在了SpringValidatorAdapter中,其中的一個(gè)屬性targetValidator就是org.hibernate.validator.internal.engine.ValidatorImpl,他實(shí)現(xiàn)了javax.validation.Validator。

    出現(xiàn)了!hibernate validator??!

  4. 接下來就是hibernate的邏輯了,便不在繼續(xù)探究,spring會(huì)將校驗(yàn)器中返回的Set<ConstraintViolation>進(jìn)行解析,并將錯(cuò)誤封裝在第四步中的創(chuàng)建的bindingResult中。

衍生

通過研究學(xué)習(xí)整個(gè)流程,逆向校驗(yàn)委托流程為
ValidatorAdapter->SpringValidatorAdapter->ValidatorImpl
繼而在正向驗(yàn)證一下探究了一下Validator的加載流程:

  1. org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator 通過springmvc自動(dòng)加載校驗(yàn)器
  2. org.springframework.boot.autoconfigure.validation.ValidatorAdapter#get通過ValidatorAdapter從上下文中獲取數(shù)據(jù)對(duì)象或直接從配置中獲取對(duì)象
  3. org.springframework.boot.autoconfigure.validation.ValidatorAdapter#getExistingOrCreate配置中沒有對(duì)象,就開始從上下文中獲取或創(chuàng)建一個(gè)新的,然后就從上下文中獲取了javax.validation.Validator的子類org.springframework.validation.beanvalidation.LocalValidatorFactoryBean 。
  4. org.springframework.boot.autoconfigure.validation.ValidatorAdapter#wrap對(duì)獲取到的對(duì)象進(jìn)行包裝使用。

不再探究第三步中org.springframework.validation.beanvalidation.LocalValidatorFactoryBean 的加載過程了,交給讀者探究吧。

總結(jié)

從解析的過程來看,校驗(yàn)參數(shù)發(fā)生在解析參數(shù)的時(shí)間,而不是通過過濾器來處理的,是直接框架集成的功能。所以,可能需要換種方式,考慮如何將鑒權(quán)前置,而不是想辦法將校驗(yàn)參數(shù)后置。好的,這個(gè)坑看看什么時(shí)候填。??????

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容