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

SpringBoot實現(xiàn)過濾器、攔截器與切片的實現(xiàn)和區(qū)別

 更新時間:2019年02月21日 11:23:33   作者:七印miss  
本文詳細介紹了使用過濾器、攔截器與切片實現(xiàn)每個請求耗時的統(tǒng)計,并比較三者的區(qū)別與聯(lián)系,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

Q:使用過濾器、攔截器與切片實現(xiàn)每個請求耗時的統(tǒng)計,并比較三者的區(qū)別與聯(lián)系

過濾器Filter

過濾器概念

Filter是J2E中來的,可以看做是 Servlet 的一種“加強版”,它主要用于對用戶請求進行預處理和后處理,擁有一個典型的 處理鏈 。Filter也可以對用戶請求生成響應,這一點與Servlet相同,但實際上很少會使用Filter向用戶請求生成響應。使用Filter完整的流程是:Filter對用戶請求進行預處理,接著將請求交給Servlet進行預處理并生成響應,最后Filter再對服務器響應進行后處理。

過濾器作用

在JavaDoc中給出了幾種過濾器的作用

 * Examples that have been identified for this design are<br>
 * 1) Authentication Filters, 即用戶訪問權限過濾
 * 2) Logging and Auditing Filters, 日志過濾,可以記錄特殊用戶的特殊請求的記錄等
 * 3) Image conversion Filters
 * 4) Data compression Filters <br>
 * 5) Encryption Filters <br>
 * 6) Tokenizing Filters <br>
 * 7) Filters that trigger resource access events <br>
 * 8) XSL/T filters <br>
 * 9) Mime-type chain Filter <br>

對于第一條,即使用Filter作權限過濾,其可以這么實現(xiàn):定義一個Filter,獲取每個客戶端發(fā)起的請求URL,與當前用戶無權限訪問的URL列表(可以是從DB中取出)作對比,起到權限過濾的作用。

過濾器實現(xiàn)方式

自定義的過濾器都必須實現(xiàn) javax.Servlet.Filter 接口,并重寫接口中定義的三個方法:

1、void init(FilterConfig config)
用于完成Filter的初始化。

2、void destory()
用于Filter銷毀前,完成某些資源的回收。

3、void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
實現(xiàn)過濾功能,即對每個請求及響應增加的額外的預處理和后處理。,執(zhí)行該方法之前,即對用戶請求進行預處理;執(zhí)行該方法之后,即對服務器響應進行后處理。值得注意的是, chain.doFilter() 方法執(zhí)行之前為預處理階段,該方法執(zhí)行結束即代表用戶的請求已經得到控制器處理。因此,如果再 doFilter 中忘記調用 chain.doFilter() 方法,則用戶的請求將得不到處理。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

// 必須添加注解,springmvc通過web.xml配置
@Component
public class TimeFilter implements Filter {
 private static final Logger LOG = LoggerFactory.getLogger(TimeFilter.class);

 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
  LOG.info("初始化過濾器:{}", filterConfig.getFilterName());
 }

 @Override
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  LOG.info("start to doFilter");
  long startTime = System.currentTimeMillis();
  chain.doFilter(request, response);
  long endTime = System.currentTimeMillis();
  LOG.info("the request of {} consumes {}ms.", getUrlFrom(request), (endTime - startTime));
  LOG.info("end to doFilter");
 }

 @Override
 public void destroy() {
  LOG.info("銷毀過濾器");
 }

 private String getUrlFrom(ServletRequest servletRequest){
  if (servletRequest instanceof HttpServletRequest){
   return ((HttpServletRequest) servletRequest).getRequestURL().toString();
  }

  return "";
 }
}

從代碼中可看出,類 Filter 是在 javax.servlet.* 中,因此可以看出,過濾器的一個很大的局限性在于, 其不能夠知道當前用戶的請求是被哪個控制器(Controller)處理的 ,因為后者是spring框架中定義的。

在SpringBoot中注冊第三方過濾器

對于SpringMvc,可以通過在 web.xml 中注冊過濾器。但在SpringBoot中不存在 web.xml ,此時如果引用的某個jar包中的過濾器,且這個過濾器在實現(xiàn)時沒有使用 @Component 標識為Spring Bean,則這個過濾器將不會生效。此時需要通過java代碼去注冊這個過濾器。以上面定義的 TimeFilter 為例,當去掉類注解 @Component 時,注冊方式為:

@Configuration
public class WebConfig {
 /**
  * 注冊第三方過濾器
  * 功能與spring mvc中通過配置web.xml相同
  * @return
  */
 @Bean
 public FilterRegistrationBean thirdFilter(){
  ThirdPartFilter thirdPartFilter = new ThirdPartFilter();
  FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean() ;

  filterRegistrationBean.setFilter(thirdPartFilter);
  List<String > urls = new ArrayList<>();
  // 匹配所有請求路徑
  urls.add("/*");
  filterRegistrationBean.setUrlPatterns(urls);

  return filterRegistrationBean;
 }
}

相比使用 @Component 注解,這種配置方式有個優(yōu)點,即可以自由配置攔截的URL。

攔截器Interceptor

攔截器概念

攔截器,在AOP(Aspect-Oriented Programming)中用于在某個方法或字段被訪問之前,進行攔截,然后在之前或之后加入某些操作。攔截是AOP的一種實現(xiàn)策略。

攔截器作用

  1. 日志記錄:記錄請求信息的日志,以便進行信息監(jiān)控、信息統(tǒng)計、計算PV(Page View)等
  2. 權限檢查:如登錄檢測,進入處理器檢測檢測是否登錄
  3. 性能監(jiān)控:通過攔截器在進入處理器之前記錄開始時間,在處理完后記錄結束時間,從而得到該請求的處理時間。(反向代理,如apache也可以自動記錄);
  4. 通用行為:讀取cookie得到用戶信息并將用戶對象放入請求,從而方便后續(xù)流程使用,還有如提取Locale、Theme信息等,只要是多個處理器都需要的即可使用攔截器實現(xiàn)。

 攔截器實現(xiàn)

通過實現(xiàn) HandlerInterceptor 接口,并重寫該接口的三個方法來實現(xiàn)攔截器的自定義:

1、preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)
方法將在 請求處理之前 進行調用。SpringMVC中的 Interceptor 同F(xiàn)ilter一樣都是 鏈式調用 。每個Interceptor的調用會依據它的聲明順序依次執(zhí)行,而且最先執(zhí)行的都是Interceptor中的preHandle方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續(xù)進行下去。該方法的返回值是布爾值Boolean 類型的,當它返回為false時,表示請求結束,后續(xù)的Interceptor和Controller都不會再執(zhí)行;當返回值為true時就會繼續(xù)調用下一個Interceptor 的preHandle 方法,如果已經是最后一個Interceptor 的時候就會是調用當前請求的Controller 方法。

2、 postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
在當前 請求進行處理之后 ,也就是Controller 方法調用之后執(zhí)行,但是它會在DispatcherServlet 進行視圖返回渲染之前被調用,所以我們可以在這個方法中對Controller 處理之后的ModelAndView 對象進行操作。

 3、afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
該方法也是需要當前對應的Interceptor的preHandle方法的返回值為true時才會執(zhí)行。顧名思義,該方法將在整個請求結束之后,也就是在DispatcherServlet 渲染了對應的視圖之后執(zhí)行 。這個方法的主要作用是用于進行資源清理工作的。

@Component
public class TimeInterceptor implements HandlerInterceptor {
 private static final Logger LOG = LoggerFactory.getLogger(TimeInterceptor.class);
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  LOG.info("在請求處理之前進行調用(Controller方法調用之前)");
  request.setAttribute("startTime", System.currentTimeMillis());
  HandlerMethod handlerMethod = (HandlerMethod) handler;
  LOG.info("controller object is {}", handlerMethod.getBean().getClass().getName());
  LOG.info("controller method is {}", handlerMethod.getMethod());

  // 需要返回true,否則請求不會被控制器處理
  return true;
 }

 @Override
 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  LOG.info("請求處理之后進行調用,但是在視圖被渲染之前(Controller方法調用之后),如果異常發(fā)生,則該方法不會被調用");
 }

 @Override
 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  LOG.info("在整個請求結束之后被調用,也就是在DispatcherServlet 渲染了對應的視圖之后執(zhí)行(主要是用于進行資源清理工作)");
  long startTime = (long) request.getAttribute("startTime");
  LOG.info("time consume is {}", System.currentTimeMillis() - startTime);
 }

與過濾器不同的是,攔截器使用 @Component 修飾后,還需要通過實現(xiàn) WebMvcConfigurer 手動注冊:

// java配置類
@Configuration
public class WebConfig implements WebMvcConfigurer {
 @Autowired
 private TimeInterceptor timeInterceptor;

 @Override
 public void addInterceptors(InterceptorRegistry registry){
  registry.addInterceptor(timeInterceptor);
 }
}

切片Aspect

 切片概述

相比過濾器,攔截器能夠知道用戶發(fā)出的請求最終被哪個控制器處理,但是攔截器還有一個明顯的不足,即不能夠獲取request的參數以及控制器處理之后的response。所以就有了切片的用武之地了。

切片實現(xiàn)

切片的實現(xiàn)需要注意 @Aspect , @Component 以及 @Around 這三個注解的使用,詳細查看官方文檔:傳送門

@Aspect
@Component
public class TimeAspect {
 private static final Logger LOG = LoggerFactory.getLogger(TimeAspect.class);

 @Around("execution(* me.ifight.controller.*.*(..))")
 public Object handleControllerMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
  LOG.info("切片開始。。。");
  long startTime = System.currentTimeMillis();

  // 獲取請求入參
  Object[] args = proceedingJoinPoint.getArgs();
  Arrays.stream(args).forEach(arg -> LOG.info("arg is {}", arg));

  // 獲取相應
  Object response = proceedingJoinPoint.proceed();

  long endTime = System.currentTimeMillis();
  LOG.info("請求:{}, 耗時{}ms", proceedingJoinPoint.getSignature(), (endTime - startTime));
  LOG.info("切片結束。。。");
  return null;
 }
}

過濾器、攔截器以及切片的調用順序

如下圖,展示了三者的調用順序Filter->Intercepto->Aspect->Controller。相反的是,當Controller拋出的異常的處理順序則是從內到外的。因此我們總是定義一個注解 @ControllerAdvice 去統(tǒng)一處理控制器拋出的異常。如果一旦異常被 @ControllerAdvice 處理了,則調用攔截器的 afterCompletion 方法的參數 Exception ex 就為空了。

實際執(zhí)行的調用棧也說明了這一點:

而對于過濾器和攔截器詳細的調用順序如下圖:

 

過濾器和攔截器的區(qū)別

最后有必要再說說過濾器和攔截器二者之間的區(qū)別:

Filter Interceptor
實現(xiàn)方式 過濾器是基于函數回調 基于Java的反射機制的
規(guī)范 Servlet規(guī)范 Spring規(guī)范
作用范圍 對幾乎所有的請求起作用 只對action請求起作用

除此之外,相比過濾器,攔截器能夠“看到”用戶的請求具體是被Spring框架的哪個控制器所處理。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Javac/javap 自帶工具簡單使用講解

    Javac/javap 自帶工具簡單使用講解

    這篇文章主要介紹了Javac/javap 自帶工具簡單使用講解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • 淺談使用Java Web獲取客戶端真實IP的方法示例詳解

    淺談使用Java Web獲取客戶端真實IP的方法示例詳解

    這篇文章主要介紹了使用Java-Web獲取客戶端真實IP的方法示例詳解。一般我們無法獲取客戶端真實IP,原因是:當我們通過request獲取客戶端IP時,自身服務器通常會為了保護信息或者負載均衡的目的,對自身服務器做反向代理。對此感興趣可以了解一下
    2020-07-07
  • 聊聊java中一些減少if else 的編碼習慣的方法

    聊聊java中一些減少if else 的編碼習慣的方法

    這篇文章主要介紹了聊聊java中一些減少if else 的編碼習慣的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • java多線程抓取鈴聲多多官網的鈴聲數據

    java多線程抓取鈴聲多多官網的鈴聲數據

    很容易就能發(fā)現(xiàn)通過改變 listId和page就能從服務器獲取鈴聲的json數據, 通過解析json數據, 可以看到都帶有{"hasmore":1,"curpage":1}這樣子的指示,通過判斷hasmore的值,決定是否進行下一頁的抓取。 但是通過上面這個鏈接返回的json中不帶有鈴聲的下載地址
    2016-04-04
  • EDI中JAVA通過FTP工具實現(xiàn)文件上傳下載實例

    EDI中JAVA通過FTP工具實現(xiàn)文件上傳下載實例

    這篇文章主要介紹了EDI中JAVA通過FTP工具實現(xiàn)文件上傳下載實例,具有一定的參考價值,有需要的可以了解一下。
    2016-11-11
  • Java導出CSV文件的方法

    Java導出CSV文件的方法

    這篇文章主要為大家詳細介紹了Java導出CSV文件的方法,分頁查詢大數據量,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • SpringMVC MethodArgumentResolver的作用與實現(xiàn)

    SpringMVC MethodArgumentResolver的作用與實現(xiàn)

    這篇文章主要介紹了SpringMVC MethodArgumentResolver的作用與實現(xiàn),MethodArgumentResolver采用一種策略模式,在Handler的方法被調用前,Spring MVC會自動將HTTP請求中的參數轉換成方法參數
    2023-04-04
  • Java matches類,Pattern類及matcher類用法示例

    Java matches類,Pattern類及matcher類用法示例

    這篇文章主要介紹了Java matches類,Pattern類及matcher類用法,結合實例形式分析了java matches類,Pattern類及matcher類針對字符串常見操作技巧與相關注意事項,需要的朋友可以參考下
    2019-03-03
  • Java Enum的簡單使用

    Java Enum的簡單使用

    這篇文章主要為大家詳細介紹了Java Enum的簡單使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Java實現(xiàn)簡單小畫板

    Java實現(xiàn)簡單小畫板

    這篇文章主要為大家詳細介紹了Java實現(xiàn)簡單小畫板,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評論

吉木萨尔县| 衡阳市| 马公市| 嫩江县| 黔西县| 安溪县| 海阳市| 竹北市| 莱阳市| 信阳市| 会泽县| 涟水县| 盐源县| 额敏县| 平邑县| 曲靖市| 稷山县| 邓州市| 砀山县| 莱芜市| 宁德市| 冕宁县| 阿拉善左旗| 大宁县| 九台市| 依安县| 桓仁| 两当县| 方正县| 六安市| 永仁县| 紫云| 织金县| 铁力市| 邵武市| 汶川县| 黎川县| 突泉县| 宕昌县| 屯留县| 达州市|