国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringBoot中Filter bean是怎么被添加到Servlet容器中的

這篇具有很好參考價值的文章主要介紹了SpringBoot中Filter bean是怎么被添加到Servlet容器中的。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

參考資料

對于Spring Boot的IOC容器——ServletWebServerApplicationContext,其中的Filter bean,每個Filter bean都會被獨(dú)立的注冊成為Servlet的Filter。大概的注冊過程分成2步:

  1. IOC容器——ServletWebServerApplicationContext將Filter接口的實現(xiàn)類封裝成FilterRegistrationBean,放到ServletContextInitializerBeans實例的成員變量initializers變量(LinkedMultiValueMap)中
  2. Spring 容器(ServletWebServerApplicationContext)從ServletContextInitializerBeans實例的成員變量initializers變量(LinkedMultiValueMap),中獲取所有的ServletContextInitializer實現(xiàn)類,調(diào)用它們的onStartUp函數(shù),F(xiàn)ilterRegistrationBean的onStartup函數(shù)就是在調(diào)用ServletContext的addFilter函數(shù)向Servlet添加Filter

1. IOC容器——ServletWebServerApplicationContext將Filter接口的實現(xiàn)類封裝成FilterRegistrationBean,放到ServletContextInitializerBeans實例的成員變量initializers變量(LinkedMultiValueMap)中

  1. Spring容器——ServletWebServerApplicationContext的refresh()函數(shù)被調(diào)用。
protected void onRefresh() {
    super.onRefresh();    
    try {
       createWebServer();    
       }
    catch (Throwable ex) {
       throw new ApplicationContextException("Unable to start web server", ex);   
    }
}
  1. ServletWebServerApplicationContext的createWebServer()函數(shù),
  • 在函數(shù)中會調(diào)用getSelfInitializer()函數(shù)獲取所有的ServletContextInitializer實例,
  • 而獲取所有的ServletContextInitializer實例的過程中,會查找所有實現(xiàn)了Filter接口的bean,并注冊成FilterRegistrationBean(實現(xiàn)了ServletContextInitializer接口,所以也屬于ServletContextInitializer實例),
  • 然后把FilterRegistrationBean放到initializers變量(LinkedMultiValueMap)中
private void createWebServer() {
    WebServer webServer = this.webServer;    
    ServletContext servletContext = getServletContext();    
    if (webServer == null && servletContext == null) {
       StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");       
       ServletWebServerFactory factory = getWebServerFactory();       
       createWebServer.tag("factory", factory.getClass().toString());  
       //  getSelfInitializer()函數(shù)中獲取所有ServletContextInitializer實例,調(diào)用onStartup方法完成注冊
       this.webServer = factory.getWebServer(getSelfInitializer());
       ......
}

private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
    return this::selfInitialize;
    }

private void selfInitialize(ServletContext servletContext) throws ServletException {
    prepareWebApplicationContext(servletContext);    
    registerApplicationScope(servletContext);    
    WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);  
    //   獲取所有ServletContextInitializer實例,調(diào)用onStartup方法
    for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
       beans.onStartup(servletContext);   
        }
}
// 傳入BeanFactory,new 一個ServletContextInitializerBeans對象,這個對象實現(xiàn)了Collection接口,是一個集合,
// 集合內(nèi)的元素是需要內(nèi)置在Servlet Context上的ServletContextInitializer bean
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
    return new ServletContextInitializerBeans(getBeanFactory());
    }
  1. ServletContextInitializerBeans的構(gòu)建
public ServletContextInitializerBeans(ListableBeanFactory beanFactory,       Class<? extends ServletContextInitializer>... initializerTypes) {
    this.initializers = new LinkedMultiValueMap<>();    
    this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
          : Collections.singletonList(ServletContextInitializer.class);    
     // 找直接定義為ServletContextInitializer的bean(比如FilterRegistrationBean),DelegatingFilterProxyRegistrationBean等,
     // 添加到initializers中
    addServletContextInitializerBeans(beanFactory);    
     // 找實現(xiàn)了Filter接口的bean,將他們封裝成ServletContextInitializer bean(對于Filter的實現(xiàn)類也就是封裝成FilterRegistrationBean),
     // 添加到initializers中
    addAdaptableBeans(beanFactory);   
    //排序  
    List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
          .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
          .collect(Collectors.toList());    
          this.sortedList = Collections.unmodifiableList(sortedInitializers);    
          logMappings(this.initializers);
}

protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
    MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);    
    // 獲取實現(xiàn)了Servlet接口的bean
    addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig)); 
    // 查找所有實現(xiàn)了Filter接口的bean,并注冊成FilterRegistrationBean,
    // 然后把FilterRegistrationBean放到initializers變量(LinkedMultiValueMap)中
    addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());    
    for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
       addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,             
                 new ServletListenerRegistrationBeanAdapter());    
       }
}

所以我們可以看到ServletContextInitializerBeans構(gòu)造函數(shù)是怎么構(gòu)造一個包含
ServletContextInitializer bean集合的

  • 直接定義為ServletContextInitializer的bean(比如FilterRegistrationBean),
  • DelegatingFilterProxyRegistrationBean等,添加到initializers中
    找實現(xiàn)了Filter接口的bean,將他們封裝成ServletContextInitializer bean(對于Filter的實現(xiàn)類也就是封裝成FilterRegistrationBean),添加到initializers中
  • 排序然后一并返回

所以ServletContextInitializerBeans實例表示的是:一個從ListableBeanFactory bean容器中獲得的ServletContextInitializer實例的集合。這個集合中的每個元素來自容器中定義的每個如下類型的bean :

  • 實現(xiàn)了ServletContextInitializer接口的bean
    具體可能以ServletRegistrationBean/FilterRegistrationBean/EventListenerRegistrationBean的形式存在。這些 bean 設(shè)計的目的是用來注冊相應(yīng)的 Servlet/Filter/EventListener bean 到 ServletContext
- **實現(xiàn)了Servlet/Filter/EventListener接口的 bean**

這些 bean直接以實現(xiàn)裸的Servlet/Filter/EventListener接口的 bean的形式存在,但是Springboot會將它們封裝成相應(yīng)的 RegistrationBean(也是ServletContextInitializer ),然后也注冊到ServletContext。

也就是說,Spring幫我們將實現(xiàn)裸的Servlet/Filter/EventListener接口的 bean,封裝成ServletRegistrationBean/FilterRegistrationBean/EventListenerRegistrationBean。文章來源地址http://www.zghlxwxcb.cn/news/detail-623629.html

2. Spring 容器(ServletWebServerApplicationContext)從ServletContextInitializerBeans實例的成員變量initializers變量(LinkedMultiValueMap),中獲取所有的ServletContextInitializer實現(xiàn)類,調(diào)用它們的startUp函數(shù),F(xiàn)ilterRegistrationBean的onStartup函數(shù)就是在調(diào)用ServletContext的addFilter函數(shù)向Servlet添加Filter

  1. 還是要回到上面1.2中的createWebServer()函數(shù)中,這次我們不看getSelfInitializer(),而是看factory.getWebServer(...)函數(shù)。
private void createWebServer() {
    WebServer webServer = this.webServer;    
    ServletContext servletContext = getServletContext();    
    if (webServer == null && servletContext == null) {
       StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");       
       ServletWebServerFactory factory = getWebServerFactory();       
       createWebServer.tag("factory", factory.getClass().toString());  
       //  getSelfInitializer()函數(shù)中獲取所有ServletContextInitializer實例,調(diào)用onStartup方法完成注冊
       this.webServer = factory.getWebServer(getSelfInitializer());
       ......
}
  1. TomcatServletWebServerFactory的getWebServer(...)函數(shù)
public WebServer getWebServer(ServletContextInitializer... initializers) {
    if (this.disableMBeanRegistry) {
       Registry.disableRegistry();    
    }
    ......
    // 將前面獲取到的所有ServletContextInitializer實例作為參數(shù),傳下去
    prepareContext(tomcat.getHost(), initializers);    
    return getTomcatWebServer(tomcat);
 }
  1. TomcatServletWebServerFactory的prepareContext(...)
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
    ......
    // 合并一下
    ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);    
    host.addChild(context);   
    // 將前面獲取到的所有ServletContextInitializer實例作為參數(shù),傳下去 
    configureContext(context, initializersToUse);    
    postProcessContext(context);}
  1. tomcatServletWebServerFactory的configureContext(...),創(chuàng)建了TomcatStarter,并將TomcatStarter綁定到Tomcat上,這樣Tomcat啟動時就會回調(diào)TomcatStarter的onStartup函數(shù)。
protected void configureContext(Context context, ServletContextInitializer[] initializers) {
    // 將前面獲取到的所有ServletContextInitializer實例作為參數(shù),傳下去 
    TomcatStarter starter = new TomcatStarter(initializers);
    
    // 下面這一系列操作是將TomcatStarter綁定到Tomcat上,這樣TomcatStarter就會在Tomcat啟動時被回調(diào)
    if (context instanceof TomcatEmbeddedContext) {
    TomcatEmbeddedContext embeddedContext = (TomcatEmbeddedContext) context;    
    embeddedContext.setStarter(starter);    
    embeddedContext.setFailCtxIfServletStartFails(true);
    }
    context.addServletContainerInitializer(starter, NO_CLASSES);
    ......
}
  1. TomcatStarter的startUp函數(shù)被調(diào)用的時候,就會變量所有的ServletContextInitializer實例的onStartup函數(shù),
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());       
          }
    }
}
  1. 回顧第一章:“Filter接口的實現(xiàn)類封裝成FilterRegistrationBean”,而FilterRegistrationBean又是ServletContextInitializer接口的實現(xiàn)類,所以上面第5步,也會回調(diào)FilterRegistrationBean的onStartup函數(shù),
//FilterRegistrationBean
public final void onStartup(ServletContext servletContext) throws ServletException {
    String description = getDescription();    
    if (!isEnabled()) {
       logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");       return;    
       }
    // 這里
    register(description, servletContext);
}
  1. DynamicRegistrationBean.class
protected final void register(String description, ServletContext servletContext) {
    //這里
    D registration = addRegistration(description, servletContext);    
    if (registration == null) {
       logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");       
       return;    
       }
    configure(registration);
    }
  1. AbstractFilterRegistrationBean.class, 看到?jīng)],最終還是用ServletContext的addFilter函數(shù),向Servlet容器中添加Filter。
protected Dynamic addRegistration(String description, ServletContext servletContext) {
    // getFilter()在FilterRegistrationBean中被實現(xiàn),返回的就是那個Filter接口的實現(xiàn)類。
    Filter filter = getFilter();   
    // 將Filter接口的實現(xiàn)類添加到Servlet容器中 
    return servletContext.addFilter(getOrDeduceName(filter), filter);
  }

到了這里,關(guān)于SpringBoot中Filter bean是怎么被添加到Servlet容器中的的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 73.是否可以把我們所需的Bean都放入Spring-mvc子容器里面來管理(springmvc的spring-servlet.xml中配置全局掃描)?

    可以 , 因為父容器的體現(xiàn)無非是為了獲取子容器不包含的bean, 如果全部包含在子容器完全用不到父容器了, 所以是可以全部放在springmvc子容器來管理的。 雖然可以這么做不過一般應(yīng)該是不推薦這么去做的,一般人也不會這么干的。如果你的項目里有用到事物、或者aop記得也

    2024年02月21日
    瀏覽(25)
  • Servlet容器中的會話管理設(shè)計說明

    Servlet容器是一種用于運(yùn)行Java Servlet的容器,它是Web服務(wù)器的一部分。它負(fù)責(zé)處理Servlet的生命周期、請求和響應(yīng)處理、多線程處理、會話管理等任務(wù)。 以下是Servlet容器架構(gòu)的主要設(shè)計說明: Servlet容器架構(gòu)通常是基于分層結(jié)構(gòu)設(shè)計的。最底層是網(wǎng)絡(luò)層,負(fù)責(zé)接收和發(fā)送請求和

    2024年02月15日
    瀏覽(16)
  • SpringBoot復(fù)習(xí):(20)如何把bean手動注冊到容器?

    可以通過實現(xiàn)BeanDefinitionRegistryPostProcessor接口,它的父接口是BeanFactoryPostProcessor. 步驟: 一、自定義一個組件類: 二、定義類實現(xiàn)BeanDefinitionRegistryPostProcessor: 通過@Component注解,Spring就能夠掃描到MyBeanDefinitionRegistryPostProcessor,也就能夠把MusicService這個組件注冊到容器。 三、可

    2024年02月14日
    瀏覽(17)
  • 手寫自己的Springboot-2-從Servlet容器選擇徹底理解自動配置

    手寫自己的Springboot-2-從Servlet容器選擇徹底理解自動配置

    如果還沒有看第一篇文章的伙伴,建議先看第一篇文章 手寫自己的Springboot-1-整合tomcat,該文章在第一篇文章基礎(chǔ)上進(jìn)行擴(kuò)展. 在我們使用Springboot時,如果不想用Tomcat,想用Jetty,應(yīng)該怎么辦呢? 其實很簡單,我們只需要把Tomcat的依賴排除掉,然后引入Jetty即可. 那Springboot底層究竟是怎樣

    2024年02月05日
    瀏覽(22)
  • 【SpringBoot】詳細(xì)介紹SpringBoot中的bean

    在Spring Boot中,Bean是由Spring容器實例化、管理和維護(hù)的對象。Bean是Spring框架的核心概念之一,它代表了應(yīng)用程序中的組件或?qū)ο蟆?以下是有關(guān)Spring Boot中Bean的詳細(xì)介紹: 1. 定義 : Bean是在Spring容器中被實例化、管理和維護(hù)的對象。一個Bean可以是任何普通的Java對象 ,例如

    2024年02月11日
    瀏覽(28)
  • SpringBoot中的bean管理

    SpringBoot中的bean管理

    默認(rèn) 情況下,Spring項目啟動時,會把bean都創(chuàng)建好放在IOC容器中,如果想要主動獲取這些bean,可以通過如下方式: 根據(jù) name 獲取bean: 根據(jù) 類型 獲取bean: 根據(jù) name 獲取bean(帶 類型 轉(zhuǎn)換) : 示例: 上述所說的【Spring項目啟動時,會把其中的bean都創(chuàng)建好】還會受到 作用域 及 延遲

    2024年02月11日
    瀏覽(19)
  • springboot3整合elasticsearch8.7.0實現(xiàn)為bean對象創(chuàng)建索引添加映射

    springboot3整合elasticsearch8.7.0實現(xiàn)為bean對象創(chuàng)建索引添加映射

    目錄 準(zhǔn)備工作 添加相關(guān)依賴 在yml中配置elasticsearch 主要內(nèi)容 實體類 ElasticSearch配置類 測試 確認(rèn)當(dāng)前沒有counter索引 啟動spring 再次查詢counter索引? 在測試類中輸出counter索引的映射 官方文檔 要注意版本對應(yīng)關(guān)系 spring官方文檔中有版本對照表 目前我使用的都是最新的版本,

    2024年02月03日
    瀏覽(20)
  • Docker已存在的容器,怎么(添加新端口號·圖文詳解)

    Docker已存在的容器,怎么(添加新端口號·圖文詳解)

    有些時候我們在創(chuàng)建容器時就已經(jīng)想好這個容器內(nèi)部端口映射那些外部端口,但是隨時業(yè)務(wù)的變化我們可能需要添加新的端口信息,以供外部訪問! 1.查看容器的端口映射情況: docker port 容器id 2.查詢?nèi)萜髟诒緳C(jī)位置 docker inspect 容器 | grep 容器 進(jìn)入容器目錄需要修改2個文件 confi

    2024年02月05日
    瀏覽(17)
  • 16、Web原生組件注入(Servlet、Filter、Listener)

    16、Web原生組件注入(Servlet、Filter、Listener)

    【尚硅谷】SpringBoot2零基礎(chǔ)入門教程-講師:雷豐陽 筆記 路還在繼續(xù),夢還在期許 推薦使用原生Servlet API 這種方式 使用 Servlet 3.0 版本以上提供的原生注解。 @WebServlet(urlPatterns = “/my”) 效果:不需要在web.xml寫配置,直接響應(yīng),沒有經(jīng)過Spring的攔截器,urlPatterns :訪問路徑。

    2023年04月20日
    瀏覽(35)
  • Spring Boot 3.1.2版本使用javax.servlet.Filter時,發(fā)現(xiàn)Filter不起作用

    Spring Boot 3.1.2版本使用javax.servlet.Filter時,發(fā)現(xiàn)Filter不起作用

    在學(xué)習(xí)Filter的過程中,我實現(xiàn)了Filter的init和destory方法以及doFilter方法后,運(yùn)行SpringBoot程序發(fā)現(xiàn),我的控制臺中并沒有輸出ini和destory中的調(diào)試信息。 代碼如下: ?可以看到控制臺中并沒有輸出initialize Filter和destory Filter等信息 ?利用postman發(fā)送http請求發(fā)現(xiàn)access Filter也沒有輸出

    2024年03月09日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包