最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中攔截器和動(dòng)態(tài)代理的區(qū)別詳解

 更新時(shí)間:2023年09月15日 14:15:09   作者:Java中文社群  
在?Spring?Boot?中,攔截器和動(dòng)態(tài)代理都是用來(lái)實(shí)現(xiàn)功能增強(qiáng)的,所以在很多時(shí)候,有人會(huì)認(rèn)為攔截器的底層是通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的,所以本文就來(lái)盤點(diǎn)一下他們兩的區(qū)別,以及攔截器的底層實(shí)現(xiàn)吧

1.攔截器

攔截器(Interceptor)準(zhǔn)確來(lái)說(shuō)在 Spring MVC 中的一個(gè)很重要的組件,用于攔截 Controller 的請(qǐng)求。它的主要作用有以下幾個(gè):

  • 權(quán)限驗(yàn)證:驗(yàn)證用戶是否登錄、是否有權(quán)限訪問(wèn)某個(gè)接口。
  • 日志記錄:記錄請(qǐng)求信息的日志,如請(qǐng)求參數(shù),響應(yīng)信息等。
  • 性能監(jiān)控:監(jiān)控系統(tǒng)的運(yùn)行性能,如慢查詢接口等。
  • 通用行為:插入一些通用的行為,比如開(kāi)發(fā)環(huán)境忽略某些請(qǐng)求。

典型的使用場(chǎng)景是身份認(rèn)證、授權(quán)檢查、請(qǐng)求日志記錄等。

1.1 攔截器實(shí)現(xiàn)

在 Spring Boot 中攔截器的實(shí)現(xiàn)分為兩步:

  • 創(chuàng)建一個(gè)普通的攔截器,實(shí)現(xiàn) HandlerInterceptor 接口,并重寫接口中的相關(guān)方法。
  • 將上一步創(chuàng)建的攔截器加入到 Spring Boot 的配置文件中,并配置攔截規(guī)則。

具體實(shí)現(xiàn)如下。

① 實(shí)現(xiàn)自定義攔截器

import?org.springframework.stereotype.Component;
import?org.springframework.web.servlet.HandlerInterceptor;
import?org.springframework.web.servlet.ModelAndView;
import?javax.servlet.http.HttpServletRequest;
import?javax.servlet.http.HttpServletResponse;
@Component
public?class?TestInterceptor?implements?HandlerInterceptor?{
????@Override
????public?boolean?preHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler)?throws?Exception?{
????????System.out.println("攔截器:執(zhí)行 preHandle 方法。");
????????return?true;
????}
????@Override
????public?void?postHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler,?ModelAndView?modelAndView)?throws?Exception?{
????????System.out.println("攔截器:執(zhí)行 postHandle 方法。");
????}
????@Override
????public?void?afterCompletion(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler,?Exception?ex)?throws?Exception?{
????????System.out.println("攔截器:執(zhí)行 afterCompletion 方法。");
????}
}

其中:

  • boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle):在請(qǐng)求方法執(zhí)行前被調(diào)用,也就是調(diào)用目標(biāo)方法之前被調(diào)用。比如我們?cè)诓僮鲾?shù)據(jù)之前先要驗(yàn)證用戶的登錄信息,就可以在此方法中實(shí)現(xiàn),如果驗(yàn)證成功則返回 true,繼續(xù)執(zhí)行數(shù)據(jù)操作業(yè)務(wù);否則就返回 false,后續(xù)操作數(shù)據(jù)的業(yè)務(wù)就不會(huì)被執(zhí)行了。
  • void postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView):調(diào)用請(qǐng)求方法之后執(zhí)行,但它會(huì)在 DispatcherServlet 進(jìn)行渲染視圖之前被執(zhí)行。
  • void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex):會(huì)在整個(gè)請(qǐng)求結(jié)束之后再執(zhí)行,也就是在 DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后再執(zhí)行。

② 配置攔截規(guī)則

然后,我們?cè)賹⑸厦娴臄r截器注入到項(xiàng)目配置文件中,并設(shè)置相應(yīng)攔截規(guī)則,具體實(shí)現(xiàn)代碼如下:

import?org.springframework.beans.factory.annotation.Autowired;
import?org.springframework.context.annotation.Configuration;
import?org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import?org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public?class?AppConfig?implements?WebMvcConfigurer?{
????//?注入攔截器
????@Autowired
????private?TestInterceptor?testInterceptor;
????@Override
????public?void?addInterceptors(InterceptorRegistry?registry)?{
????????registry.addInterceptor(testInterceptor)?//?添加攔截器
????????????????.addPathPatterns("/**");?//?攔截所有地址
??????????.excludePathPatterns("/login");?//?放行接口
????}
}

這樣我們的攔截器就實(shí)現(xiàn)完了。

1.2 攔截器實(shí)現(xiàn)原理

Spring Boot 攔截器是基于 Java 的 Servlet 規(guī)范實(shí)現(xiàn)的,通過(guò)實(shí)現(xiàn) HandlerInterceptor 接口來(lái)實(shí)現(xiàn)攔截器功能。

在 Spring Boot 框架的執(zhí)行流程中,攔截器被注冊(cè)在 DispatcherServlet 的 doDispatch() 方法中,該方法是 Spring Boot 框架的核心方法,用于處理請(qǐng)求和響應(yīng)。

程序每次執(zhí)行時(shí)都會(huì)調(diào)用 doDispatch() 方法時(shí),并驗(yàn)證攔截器(鏈),之后再根據(jù)攔截器返回的結(jié)果,進(jìn)行下一步的處理。如果返回的是 true,那么繼續(xù)調(diào)用目標(biāo)方法,反之則會(huì)直接返回驗(yàn)證失敗給前端。

doDispatch  源碼實(shí)現(xiàn)如下:

protected?void?doDispatch(HttpServletRequest?request,?HttpServletResponse?response)?throws?Exception?{
????HttpServletRequest?processedRequest?=?request;
????HandlerExecutionChain?mappedHandler?=?null;
????boolean?multipartRequestParsed?=?false;
????WebAsyncManager?asyncManager?=?WebAsyncUtils.getAsyncManager(request);
????try?{
????????try?{
????????????ModelAndView?mv?=?null;
????????????Object?dispatchException?=?null;
????????????try?{
????????????????processedRequest?=?this.checkMultipart(request);
????????????????multipartRequestParsed?=?processedRequest?!=?request;
????????????????mappedHandler?=?this.getHandler(processedRequest);
????????????????if?(mappedHandler?==?null)?{
????????????????????this.noHandlerFound(processedRequest,?response);
????????????????????return;
????????????????}
????????????????HandlerAdapter?ha?=?this.getHandlerAdapter(mappedHandler.getHandler());
????????????????String?method?=?request.getMethod();
????????????????boolean?isGet?=?HttpMethod.GET.matches(method);
????????????????if?(isGet?||?HttpMethod.HEAD.matches(method))?{
????????????????????long?lastModified?=?ha.getLastModified(request,?mappedHandler.getHandler());
????????????????????if?((new?ServletWebRequest(request,?response)).checkNotModified(lastModified)?&&?isGet)?{
????????????????????????return;
????????????????????}
????????????????}
????????????????//?調(diào)用預(yù)處理【重點(diǎn)】
????????????????if?(!mappedHandler.applyPreHandle(processedRequest,?response))?{
????????????????????return;
????????????????}
????????????????//?執(zhí)行?Controller?中的業(yè)務(wù)
????????????????mv?=?ha.handle(processedRequest,?response,?mappedHandler.getHandler());
????????????????if?(asyncManager.isConcurrentHandlingStarted())?{
????????????????????return;
????????????????}
????????????????this.applyDefaultViewName(processedRequest,?mv);
????????????????mappedHandler.applyPostHandle(processedRequest,?response,?mv);
????????????}?catch?(Exception?var20)?{
????????????????dispatchException?=?var20;
????????????}?catch?(Throwable?var21)?{
????????????????dispatchException?=?new?NestedServletException("Handler?dispatch?failed",?var21);
????????????}
????????????this.processDispatchResult(processedRequest,?response,?mappedHandler,?mv,?(Exception)dispatchException);
????????}?catch?(Exception?var22)?{
????????????this.triggerAfterCompletion(processedRequest,?response,?mappedHandler,?var22);
????????}?catch?(Throwable?var23)?{
????????????this.triggerAfterCompletion(processedRequest,?response,?mappedHandler,?new?NestedServletException("Handler?processing?failed",?var23));
????????}
????}?finally?{
????????if?(asyncManager.isConcurrentHandlingStarted())?{
????????????if?(mappedHandler?!=?null)?{
????????????????mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest,?response);
????????????}
????????}?else?if?(multipartRequestParsed)?{
????????????this.cleanupMultipart(processedRequest);
????????}
????}
}

從上述源碼可以看出在開(kāi)始執(zhí)行 Controller 之前,會(huì)先調(diào)用 預(yù)處理方法 applyPreHandle,而 applyPreHandle 方法的實(shí)現(xiàn)源碼如下:

boolean?applyPreHandle(HttpServletRequest?request,?HttpServletResponse?response)?throws?Exception?{
????for(int?i?=?0;?i?<?this.interceptorList.size();?this.interceptorIndex?=?i++)?{
????????//?獲取項(xiàng)目中使用的攔截器?HandlerInterceptor
????????HandlerInterceptor?interceptor?=?(HandlerInterceptor)this.interceptorList.get(i);
????????if?(!interceptor.preHandle(request,?response,?this.handler))?{
????????????this.triggerAfterCompletion(request,?response,?(Exception)null);
????????????return?false;
????????}
????}
????return?true;
}

從上述源碼可以看出,在 applyPreHandle 中會(huì)獲取所有的攔截器 HandlerInterceptor 并執(zhí)行攔截器中的 preHandle 方法,這樣就會(huì)咱們前面定義的攔截器對(duì)應(yīng)上了,如下圖所示:

此時(shí)用戶登錄權(quán)限的驗(yàn)證方法就會(huì)執(zhí)行,這就是攔截器的執(zhí)行過(guò)程。因此,可以得出結(jié)論,攔截器的實(shí)現(xiàn)主要是依賴 Servlet 或 Spring 執(zhí)行流程來(lái)進(jìn)行攔截和功能增強(qiáng)的。

2.動(dòng)態(tài)代理

動(dòng)態(tài)代理是一種設(shè)計(jì)模式,它是指在運(yùn)行時(shí)提供代理對(duì)象,來(lái)擴(kuò)展目標(biāo)對(duì)象的功能。在 Spring 中的,動(dòng)態(tài)代理的實(shí)現(xiàn)手段有以下兩種:

  • JDK 動(dòng)態(tài)代理:通過(guò)反射機(jī)制生成代理對(duì)象,目標(biāo)對(duì)象必須實(shí)現(xiàn)接口。
  • CGLIB 動(dòng)態(tài)代理:通過(guò)生成目標(biāo)類的子類來(lái)實(shí)現(xiàn)代理,不要求目標(biāo)對(duì)象實(shí)現(xiàn)接口。

動(dòng)態(tài)代理的主要作用包括:

  • 擴(kuò)展目標(biāo)對(duì)象的功能:如添加日志、驗(yàn)證參數(shù)等。
  • 控制目標(biāo)對(duì)象的訪問(wèn):如進(jìn)行權(quán)限控制。
  • 延遲加載目標(biāo)對(duì)象:在需要時(shí)才實(shí)例化目標(biāo)對(duì)象。
  • 遠(yuǎn)程代理:將請(qǐng)求轉(zhuǎn)發(fā)到遠(yuǎn)程的目標(biāo)對(duì)象上。

3.攔截器 VS 動(dòng)態(tài)代理

因此,我們可以得出結(jié)論,攔截器和動(dòng)態(tài)代理雖然都是用來(lái)實(shí)現(xiàn)功能增強(qiáng)的,但二者完全不同,他們的主要區(qū)別體現(xiàn)在以下幾點(diǎn):

  • 使用范圍不同:攔截器通常用于 Spring MVC 中,主要用于攔截 Controller 請(qǐng)求。動(dòng)態(tài)代理可以使用在 Bean 中,主要用于提供 bean 的代理對(duì)象,實(shí)現(xiàn)對(duì) bean 方法的攔截。
  • 實(shí)現(xiàn)原理不同:攔截器是通過(guò) HandlerInterceptor 接口來(lái)實(shí)現(xiàn)的,主要是通過(guò) afterCompletion、postHandle、preHandle 這三個(gè)方法在請(qǐng)求前后進(jìn)行攔截處理。動(dòng)態(tài)代理主要有 JDK 動(dòng)態(tài)代理和 CGLIB 動(dòng)態(tài)代理,JDK 通過(guò)反射生成代理類;CGLIB 通過(guò)生成被代理類的子類來(lái)實(shí)現(xiàn)代理。
  • 加入時(shí)機(jī)不同:攔截器是在運(yùn)行階段動(dòng)態(tài)加入的;動(dòng)態(tài)代理是在編譯期或運(yùn)行期生成的代理類。
  • 使用難易程度不同:攔截器相對(duì)簡(jiǎn)單,通過(guò)實(shí)現(xiàn)接口即可使用。動(dòng)態(tài)代理稍微復(fù)雜,需要了解動(dòng)態(tài)代理的實(shí)現(xiàn)原理,然后通過(guò)相應(yīng)的 api 實(shí)現(xiàn)。

小結(jié)

在 Spring Boot 中,攔截器和動(dòng)態(tài)代理都是用來(lái)實(shí)現(xiàn)功能增強(qiáng)的,但二者沒(méi)有任何關(guān)聯(lián)關(guān)系,它的區(qū)別主要體現(xiàn)在使用范圍、實(shí)現(xiàn)原理、加入時(shí)機(jī)和使用的難易程度都是不同的。

以上就是SpringBoot中攔截器和動(dòng)態(tài)代理的區(qū)別詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot攔截器和動(dòng)態(tài)代理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java數(shù)字圖像處理基礎(chǔ)使用imageio寫圖像文件示例

    java數(shù)字圖像處理基礎(chǔ)使用imageio寫圖像文件示例

    這篇文章主要介紹了Java 2D的圖像處理API,文章討論和提及的API都是基于JDK6的,Java中寫一個(gè)圖像文件使用ImageIO對(duì)象即可,下面看代碼吧
    2014-01-01
  • Java中IOException異常解決方法

    Java中IOException異常解決方法

    這篇文章主要給大家介紹了關(guān)于Java中IOException異常解決的相關(guān)資料,IOException是Java中的一個(gè)受檢查異常(Checked?Exception),它是java.io包中定義的異常類之一,需要的朋友可以參考下
    2023-07-07
  • MyBatis常用動(dòng)態(tài)sql大總結(jié)

    MyBatis常用動(dòng)態(tài)sql大總結(jié)

    這篇文章主要給大家介紹了關(guān)于MyBatis常用動(dòng)態(tài)sql的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • SpringBoot 如何自定義請(qǐng)求參數(shù)校驗(yàn)

    SpringBoot 如何自定義請(qǐng)求參數(shù)校驗(yàn)

    這篇文章主要介紹了SpringBoot 如何自定義請(qǐng)求參數(shù)校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringBoot+Kotlin中使用GRPC實(shí)現(xiàn)服務(wù)通信的示例代碼

    SpringBoot+Kotlin中使用GRPC實(shí)現(xiàn)服務(wù)通信的示例代碼

    本文主要介紹了SpringBoot+Kotlin中使用GRPC實(shí)現(xiàn)服務(wù)通信的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 新手學(xué)習(xí)Java對(duì)Redis簡(jiǎn)單操作

    新手學(xué)習(xí)Java對(duì)Redis簡(jiǎn)單操作

    這篇文章主要介紹了新手學(xué)習(xí)Java對(duì)Redis簡(jiǎn)單操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 教你怎么用Java完成人民幣大寫轉(zhuǎn)化

    教你怎么用Java完成人民幣大寫轉(zhuǎn)化

    這篇文章主要介紹了教你怎么用Java完成人民幣大寫轉(zhuǎn)化,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-04-04
  • SparkSQL使用IDEA快速入門DataFrame與DataSet的完美教程

    SparkSQL使用IDEA快速入門DataFrame與DataSet的完美教程

    本文給大家介紹使用idea開(kāi)發(fā)Spark SQL 的詳細(xì)過(guò)程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-08-08
  • java對(duì)象初始化順序驗(yàn)證示例

    java對(duì)象初始化順序驗(yàn)證示例

    以下這段小程序?qū)φ{(diào)用對(duì)象構(gòu)造函數(shù)時(shí),父類構(gòu)造函數(shù)、成員變量初始化函數(shù),以及非靜態(tài)初始化塊調(diào)用順序進(jìn)行驗(yàn)證,不考慮靜態(tài)成員及靜態(tài)初始化塊
    2014-02-02
  • Java讓泛型實(shí)例化的方法

    Java讓泛型實(shí)例化的方法

    這篇文章主要介紹了Java讓泛型實(shí)例化的方法,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07

最新評(píng)論

石渠县| 汉源县| 鄂托克前旗| 肥东县| 北碚区| 额济纳旗| 新绛县| 永新县| 通山县| 夏津县| 武乡县| 龙游县| 桃源县| 大姚县| 阿合奇县| 宁远县| 进贤县| 大同市| 金门县| 大庆市| 邵阳市| 杭锦旗| 墨玉县| 苍溪县| 济南市| 东乌珠穆沁旗| 西藏| 焦作市| 民权县| 武定县| 蓬安县| 朔州市| 南开区| 北碚区| 云阳县| 洪湖市| 榆中县| 分宜县| 红原县| 滨海县| 田东县|