ServletContextInitializer添加 servlet filter listener


ServletContextInitializer添加 servlet filter listener 

https://www.cnblogs.com/pomer-huang/p/9639322.html

 

關於springboot中添加Filter的方法

https://www.jianshu.com/p/3d421fbce734

 ———————————————————————————————————————————————————————————————

 

Spring Boot Servlet : ServletContextInitializer

概述

功能介紹

Spring Boot提供的在Servlet 3.0+環境中用於程序化配置ServletContext的接口。該接口ServletContextInitializer主要被RegistrationBean實現用於往ServletContext容器中注冊Servlet,Filter或者EventListener。這些ServletContextInitializer的設計目的主要是用於這些實例被Spring IoC容器管理。這些ServletContextInitializer實例不會被SpringServletContainerInitializer檢測,因此不會被Servlet容器自動啟動。

該接口ServletContextInitializerSpring Web的另外一個接口WebApplicationInitializer看起來幾乎一模一樣。但二者使用目的不同。Spring Web中,WebApplicationInitializer也是針對Servlet 3.0+環境,設計用於程序化配置ServletContext,跟傳統的web.xml相對或者配合使用。WebApplicationInitializer實現類會被SpringServletContainerInitializer自動檢測和啟動。

繼承關系

RegistrationBean的繼承關系

使用

關於ServletContextInitializer的應用可以參考下面的例子。TomcatStarterSpring Boot Web Servlet應用結合Tomcat使用時的一個ServletContainerInitializer實現。從下面代碼不難看出,一組ServletContextInitializer會被設置到ServletContainerInitializer TomcatStarter上,而TomcatStarterServlet容器啟動過程中調用自己的方法#onStartup,會逐一調用這些ServletContextInitializer的方法#onStartup初始化ServletContext

package org.springframework.boot.web.embedded.tomcat; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.boot.web.servlet.ServletContextInitializer; class TomcatStarter implements ServletContainerInitializer { private static final Log logger = LogFactory.getLog(TomcatStarter.class); // 使用者會指定一組 ServletContextInitializer 給 TomcatStarter private final ServletContextInitializer[] initializers; private volatile Exception startUpException; TomcatStarter(ServletContextInitializer[] initializers) { this.initializers = initializers; } // Servlet 容器啟動時回會用該方法,該方法會逐一調用每個 ServletContextInitializer 的方法 // #onStartup 會指定 ServletContext 進行初始化。這些 ServletContextInitializer 的目的 // 通常會是 注冊 Servlet, Filter 或者 EventListener 。 @Override public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException { try { for (ServletContextInitializer initializer : this.initializers) { initializer.onStartup(servletContext); } } catch (Exception ex) { this.startUpException = ex; // Prevent Tomcat from logging and re-throwing when we know we can // deal with it in the main thread, but log for information here. if (logger.isErrorEnabled()) { logger.error("Error starting Tomcat context. Exception: " + ex.getClass().getName() + ". Message: " + ex.getMessage()); } } } public Exception getStartUpException() { return this.startUpException; } } 

 

源代碼

源代碼版本 : 2.1.3.RELEASE

package org.springframework.boot.web.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.springframework.web.SpringServletContainerInitializer; import org.springframework.web.WebApplicationInitializer; @FunctionalInterface public interface ServletContextInitializer { /** * Configure the given ServletContext with any servlets, filters, listeners * context-params and attributes necessary for initialization. * @param servletContext the ServletContext to initialize * @throws ServletException if any call against the given ServletContext * throws a ServletException */ void onStartup(ServletContext servletContext) throws ServletException; } 

 

參考文章

 

——————————————————————————————————————————————————————————————————

springboot 2.1.3.RELEASE添加filter,servlet源碼學習

 

Servlet規范中,通過ServeltContext來注冊Filter、Servlet,這里分析Filter,Servlet是相同邏輯

springboot2.0中,我們通過

FilterRegistrationBean將指定得filter來實現ServeltContext注冊filter

1
2
3
4
5
6
7
8
9
10
11
12
13
FilterRegistrationBean的實例化過程
 
public  FilterRegistrationBean(T filter, ServletRegistrationBean... servletRegistrationBeans) {
         super (servletRegistrationBeans);
         Assert.notNull(filter,  "Filter must not be null" );
         this .filter = filter;
}
 
super 的實例化
AbstractFilterRegistrationBean(ServletRegistrationBean... servletRegistrationBeans) {
         Assert.notNull(servletRegistrationBeans,  "ServletRegistrationBeans must not be null" );
         Collections.addAll( this .servletRegistrationBeans, servletRegistrationBeans);
}

可知FilterRegistrationBean得實例化過程就是將Filter保存到servletRegistrationBeans(一個set)中

再分析FilterRegistrationBean類

FilterRegistrationBean的父類是一個ServletContextInitializer,他有一個方法onStartup(ServletContext servletContext)
其結果最終會調用
servletContext.addFilter(this.getOrDeduceName(filter), filter)
現在看看ServletContextInitializer.onStartup的調用地方
1
2
3
4
5
6
7
8
9
10
11
12
springboot啟動
new  SpringApplication(XXApplication. class ).run(XXApplication. class ,args)
調用
refreshContext(context); -> refresh(context); -> ((AbstractApplicationContext) applicationContext).refresh();
-> ServletWebServerApplicationContext.onRefresh(); -> createWebServer();
 
WebServer webServer =  this .webServer;
ServletContext servletContext = getServletContext();
if  (webServer ==  null  && servletContext ==  null ) {
     ServletWebServerFactory factory = getWebServerFactory();
     this .webServer = factory.getWebServer(getSelfInitializer());
}

再分析getSelfInitializer方法

1
2
3
4
prepareWebApplicationContext(servletContext);
         registerApplicationScope(servletContext);
         WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),servletContext);
         for  (ServletContextInitializer beans :getServletContextInitializerBeans()) {              
       //調用ServletContextInitializer的onStartup方法
1
beans.onStartup(servletContext);
}
-> getServletContextInitializerBeans()
1
2
->  new  ServletContextInitializerBeans(getBeanFactory())
-> addAdaptableBeans(beanFactory)

 

1
2
3
4
5
6
7
8
addAdaptableBeans(ListableBeanFactory beanFactory) 代碼如下:
MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
//將servlet類的bean包裝為ServletRegistrationBean
addAsRegistrationBean(beanFactory, Servlet. class , new  ServletRegistrationBeanAdapter(multipartConfig));
//將Filter的bean包裝為FilterRegistrationBean
addAsRegistrationBean(beanFactory, Filter. class , new  FilterRegistrationBeanAdapter());
for  (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes())
{         
addAsRegistrationBean(beanFactory, EventListener. class ,(Class<EventListener>) listenerType, new  ServletListenerRegistrationBeanAdapter());
}

 這里提一下,如果Servlet的bean實例名為dispatcherServlet,且該實例在seen集合中(seen集合為自定義配置的實例,通過ServletContextInitializerBeans.addServletContextInitializerBean入口可以查看源碼),則設置默認值為  /

1
2
3
4
5
6
7
String url = (totalNumberOfSourceBeans !=  1 ) ?  "/"  + name +  "/"  "/" ;
if  (name.equals(DISPATCHER_SERVLET_NAME)) {
     url =  "/" // always map the main dispatcherServlet to "/"
}
ServletRegistrationBean<Servlet> bean =  new  ServletRegistrationBean<>(source,url); 
bean.setName(name);
bean.setMultipartConfig( this .multipartConfig);
return  bean;

 

總結:springboot啟動時,會將所有的 FilterRegistrationBean、ServletRegistrationBean以及被spring管理的Servlet和Filter的實例,通過          ServletContext注冊Servlet以及Filter


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM