大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動(dòng)力節(jié)點(diǎn)LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 學(xué)習(xí)攻略 Java學(xué)習(xí) Java過濾器鏈的原理分析

Java過濾器鏈的原理分析

更新時(shí)間:2022-08-10 12:36:09 來源:動(dòng)力節(jié)點(diǎn) 瀏覽1310次

在很多Java Web項(xiàng)目中,我們會(huì)在web.xml中配置一些過濾器來攔截請(qǐng)求,比如下面的編碼過濾器來解決亂碼:

<過濾器>
	<filter-name>encodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<初始化參數(shù)>
		<param-name>編碼</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
	<初始化參數(shù)>
		<param-name>forceEncoding</param-name>
		<param-value>真</param-value>
	</init-param>
	</過濾器>
<過濾器映射>
	<filter-name>encodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

誰調(diào)用了這些過濾器?誰組織了他們并確保了他們的執(zhí)行順序?過濾器演示如下:

@WebFilter(filterName="FilterDemo", urlPatterns={"/**"})
@Order(1)//當(dāng)有多個(gè)過濾器時(shí),指定過濾器的順序
公共類 SecurityFilter 實(shí)現(xiàn) Filter{
	private static final Logger LOGGER = LoggerFactory.getLogger(FilterDemo.class);	
	@Override
	公共無效銷毀(){		
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			拋出 IOException,ServletException {
		//TODO 做一些過濾動(dòng)作;
		鏈.doFilter(請(qǐng)求,響應(yīng));
	}
	@Override
	公共無效初始化(FilterConfig arg0)拋出 ServletException {
		//TODO 自動(dòng)生成的方法存根	}
}

本以為這樣寫后過濾器會(huì)起作用,但是請(qǐng)求進(jìn)來后,發(fā)現(xiàn)過濾器沒有執(zhí)行。后來想到 Spring 的工作是由 beanFactry 中注冊(cè)的每個(gè) bean 完成的,所以可能需要在 beanFactory 中注冊(cè)這個(gè)過濾器,像這樣:

@Configuration//表示這是一個(gè)Spring配置文件
@EnableSwagger2//swagger是一個(gè)restful接口文檔在線自動(dòng)生成+功能測(cè)試功能框架
@RefreshScope//允許依賴配置的bean在Spring cloud config配置文件更改后無需重啟服務(wù)即可自動(dòng)更新
公共類 GlobalBeanConfig {
   //將過濾器添加到Spring配置中,否則只會(huì)寫過濾器類,不添加配置不起作用
    @Bean//使用代碼配置xml形式的<bean></bean>
    公共過濾器 filterDemo(){
        返回新的 FilterDemo();
    }
    @Bean(name = "loggerInteceptor")
    公共 GlobalAspectInteceptor getLoggerInteceptor() {
        返回新的 GlobalAspectInteceptor();
    }
    @豆
    公共 ThreadPoolTask??Executor globalTask??Executor(
            @Value("${global.thread.pool.corePoolSize}") 整數(shù) corePoolSize,
            @Value("${global.thread.pool.maxPoolSize}") 整數(shù) maxPoolSize,
            @Value("${global.thread.pool.queueCapacity}") 整數(shù) queueCapacity
    ) {
        ThreadPoolTask??Executor 執(zhí)行器 = new ThreadPoolTask??Executor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadGroupName("globalTask??Executor");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        executor.initialize();
        返回執(zhí)行者;
    }
}

添加評(píng)論后,它立即生效。既然知道了工具的使用方法,那我們就來拆解一下工具,看看效果如何。通過斷點(diǎn)調(diào)試發(fā)現(xiàn)過濾器中的兩個(gè)關(guān)鍵類在起作用:ApplicationFilterConfig和ApplicationFilterChain。

這兩個(gè)類在 org.apache.catalina.core 包下。可以肯定的是,tomcat 容器管理過濾器鏈。

接下來,我們看一下ApplicationFilterConfig,先上部分源碼:

Final 類 public ApplicationFilterConfig實(shí)現(xiàn)了 FilterConfig , Serializable {
      Private Long Final static serialVersionUID = 1L ;
 靜態(tài)最終StringManager SM = StringManager 。getManager(“org.apache.catalina.core”);
 私有靜態(tài)最終Log log = LogFactory 。getLog (
  ApplicationFilterConfig.class ) ; 私有靜態(tài)最終列表<字符串>空字符串=收藏。空列表();
 私有最終瞬態(tài)上下文上下文;
 私有瞬態(tài)過濾器 filter = null ;
 私人最終過濾器過濾器過濾器;
 私有瞬態(tài)InstanceManager instanceManager ;
 私有對(duì)象名oname ;
ApplicationFilterConfig(Context context , FilterDef filterDef) throws ClassCastException , ClassNotFoundException , IllegalAccessException , InstantiationException ,ServletException 、 InvocationTargetException 、 NamingException 、 IllegalArgumentException 、 NoSuchMethodException 、 SecurityException {
          this . 上下文=上下文;
 這個(gè)。過濾器定義=過濾器定義;
 IF (filterDef . getFilter () == null ) {
              this . getFilter () ;
}其他{
             這個(gè).過濾器=過濾器定義。getFilter () ;
這個(gè)。獲取實(shí)例管理器()。新實(shí)例(這個(gè)。過濾器);
 這個(gè)。初始化過濾器();
}
    }
}

通過分析可以發(fā)現(xiàn),這個(gè)類是用來保存一個(gè)過濾器的。構(gòu)造方法傳入的上下文必須是tomcat配置文件下context.xml配置的應(yīng)用環(huán)境。FliterDef是過濾器的描述信息,應(yīng)該通過在web.xml(或其他地方)中配置過濾器參數(shù)來構(gòu)造。

好了,重點(diǎn)來了——ApplicationFilterChain ,名字就透露了它的作用,就是它組織了分散的過濾器。結(jié)合上面我的猜測(cè),它應(yīng)該有一個(gè)數(shù)組或列表來保存ApplicationFilterConfig,以及一個(gè)過濾器光標(biāo)來記錄當(dāng)前過濾器去了哪里。源代碼(部分)如下:

public final 類ApplicationFilterChain實(shí)現(xiàn)FilterChain {
      private static final ThreadLocal < ServletRequest > lastServicedRequest ;
 private static final ThreadLocal < ServletResponse > lastServicedResponse ;
 公共靜態(tài)最終 int INCREMENT = 10 ;
 私有ApplicationFilterConfig[] 過濾器=新ApplicationFilterConfig[ 0 ] ;
 私人 int pos = 0 ;
 私人 int n = 0 ;
 私有Servlet servlet = null ;
 私有布爾servletSupportsAsync = false ;
 私有靜態(tài)最終StringManager sm ;
 private static final Class <?> [] classType ;
 私有靜態(tài)最終類<?> [] classTypeUsedInService ;
 公共應(yīng)用程序過濾器鏈(){
    }
    public void doFilter(ServletRequest request , ServletResponse response) throws IOException , ServletException {
          if (Globals . IS_SECURITY_ENABLED) {
              final ServletRequest req = request ;
 最終的 ServletResponse res = response ;
 嘗試{ 
                AccessController 。DoPrivileged( new PrivilegedExceptionAction() {
                      public Void run() throws ServletException ,IO異常{
                        應(yīng)用過濾鏈。這. InternalDoFilter(req , res) ;
 返回空值;
}                 }) ;
}捕捉(PrivilegedActionException var7){
                異常 e = var7 。獲取異常 () ;
 if (e instanceof ServletException) {
                      throw (ServletException)e ;
}
                if (e instanceof IOException) {
                      throw (IOException)e ;
}
                if (e instanceof RuntimeException) {
                      throw (RuntimeException)e ;
}
                throw new ServletException(e .getMessage () , e) ;
}
        }其他{
             這個(gè). internalDoFilter(請(qǐng)求,響應(yīng));
}
    }
    private void internalDoFilter(ServletRequest request , ServletResponse response) throws IOException , ServletException
          { if ( this.pos < this.n ) {
            ApplicationFilterConfig e1 =這個(gè)。過濾器[這個(gè)。位置++ ] ;
試試{
                過濾器 res1 = e1 。獲取過濾器();
 if (request . IsAsyncSupported() && "false" . EqualsIgnoreCase(e1 . GetFilterDef () . GetAsyncSupported ())) {
                    請(qǐng)求。setAttribute(“org.apache.catalina.ASYNC_SUPPORTED” ,布爾值。假);
}
                如果(全局。IS_SECURITY_ENABLED){
                    主體 principal1 = ((HttpServletRequest)request) 。獲取用戶主體();
Object[] args1 = new Object[]{request , response , this } ;
安全實(shí)用程序。DoAsPrivilege( "doFilter" , res1 , classType , args1 , principal1) ;
}其他{
                    水庫1 。doFilter(request , response , this ) ;
}
            } catch (ServletException | RuntimeException | IOException var15) {
                  throw var15 ;
}捕捉(可拋出的 var16){
                可拋出的res = ExceptionUtils 。UnwrapInvocationTargetException(var16) ;
異常實(shí)用程序。HandleThrowable(res) ;
 throw new ServletException( sm.GetString ( " filterChain.filter" ) , res) ;
        } else {
             嘗試{
                  if (ApplicationDispatcher . WRAP_SAME_OBJECT) {
                    最后服務(wù)請(qǐng)求。設(shè)置(請(qǐng)求);
最后服務(wù)響應(yīng)。設(shè)置(響應(yīng));
}
                if (request .isAsyncSupported () &&! this .servletSupportsAsync ) {
                    請(qǐng)求。setAttribute(“org.apache.catalina.ASYNC_SUPPORTED” ,布爾值。假);
}
                如果( HttpServletRequest的請(qǐng)求實(shí)例&& HttpServletResponse的響應(yīng)實(shí)例&&全局。IS_SECURITY_ENABLED){
                    主體主體= ((HttpServletRequest)request) 。獲取用戶主體();
Object[] args = new Object[]{request , response} ;
安全實(shí)用程序。DoAsPrivilege( "service "
 , this.Servlet , classTypeUsedInService , args , principal ) ; }其他{
                     這個(gè). 小服務(wù)程序。服務(wù)(請(qǐng)求,響應(yīng));
}
            } catch (ServletException | RuntimeException | IOException var17) {
                  throw var17 ;
}捕捉(Throwable var18){
                可拋出的e = ExceptionUtils 。UnwrapInvocationTargetException(var18) ;
異常實(shí)用程序。HandleThrowable(e) ;
 throw new ServletException( sm.GetString ( " filterChain.servlet" ) , e) ;
}最后{
                  if (ApplicationDispatcher . WRAP_SAME_OBJECT) { 
                    lastServicedRequest 。設(shè)置((對(duì)象)空);
最后服務(wù)響應(yīng)。設(shè)置((對(duì)象)空) ;
}
            }
        }
    }
    …… }

果然字段中有一個(gè)ApplicationFilterConfig[]用來存放一系列filter,pos用來存放當(dāng)前filter位置,還有其他字段就不深入了。有興趣的朋友可以自行探索。

我們來看兩個(gè)關(guān)鍵方法:doFilter、internalDoFilter

doFilter的最終目的只有一個(gè),調(diào)用internalDoFilter,中間可能會(huì)加一些安全策略,估計(jì)Globals.IS_SECURITY_ENABLE和是否開啟https服務(wù)有關(guān),具體沒有仔細(xì)研究。

internalDoFilter的最終目的只有一個(gè),就是調(diào)整當(dāng)前pos指向的filter鏈中某個(gè)filter的doFilter(request, response, this)方法。中間可能會(huì)添加一些安全策略,當(dāng)所有過濾器都被調(diào)用時(shí),進(jìn)行一些收尾工作,包括調(diào)用servlet.service(request, response)方法處理真正的請(qǐng)求,以及清除當(dāng)前存儲(chǔ)的請(qǐng)求和響應(yīng)threadLocal 為下一個(gè)請(qǐng)求做準(zhǔn)備。

再梳理一下流程:

一個(gè)請(qǐng)求進(jìn)來,先給自己給filterChain;

filterChain 啟動(dòng)過濾器鏈,從頭開始,將請(qǐng)求交給第一個(gè)過濾器,并將自身傳遞給過濾器;

Filter在doFilter中完成自己的過濾邏輯,然后調(diào)用filterChain的doFilter開始下一個(gè)過濾器;

filterChain 光標(biāo)移動(dòng),啟動(dòng)下一個(gè)過濾器,依此類推...

過濾器光標(biāo)走到鏈尾,filterChain進(jìn)行收尾工作;

最后,給出一個(gè)簡(jiǎn)單的流程圖:

提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)

免費(fèi)課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 国产精品欧美日韩一区二区 | 精品久久中文字幕有码 | 亚洲se主站 | 亚洲欧洲视频在线观看 | 久久综合九色综合91 | 色悠久久综合 | 久久中文亚洲国产 | 久久亚洲精品中文字幕 | 香蕉国产人午夜视频在线观看 | 四虎成人精品在永久免费 | 噜噜色图 | www.欧美成 | 久久综合网址 | 亚洲午夜视频在线 | 在线亚洲播放 | 色一情一欲一爱一乱 | 欧美人拘一级毛片 | 欧美xxxxx性另类 | 综合欧美亚洲 | 一级毛片在线观看免费 | 99热久久国产精品这里小说 | jizzjizzjizz中国 | 亚洲五月综合缴情婷婷 | 国产成人精品久久亚洲高清不卡 | 91在线你懂的 | 999国产精品 | 欧日韩一区二区三区 | 日韩小视频在线播放 | 99精品视频免费 | 激情网站视频 | 日韩有码在线视频 | 久久精品*5在热 | 国产精品亚洲综合 | 久色视频在线观看 | 麻豆精品久久久一区二区 | 色噜噜视频 | 狠狠狠色丁香婷婷综合久久88 | 理论大片三在线观看 | 亚洲欧美中文日韩在线 | 亚洲欧美片 | 日本不卡视频在线观看 |