日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

spring图片转视频_一直在用的 Spring,你知道它的加载原理吗?

發布時間:2024/1/23 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring图片转视频_一直在用的 Spring,你知道它的加载原理吗? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
??Java大聯盟

? 幫助萬千Java學習者持續成長

關注

作者|擁抱心中的夢想

juejin.im/post/5ab30714f265da237b21fbcc

B 站搜索:楠哥教你學Java

獲取更多優質視頻教程

一、前言

作為一個經常使用 Spring 的后端程序員,小編很早就想徹底弄懂整個 Spring 框架了!但它整體是非常大的,所有繼承圖非常復雜,加上小編修行尚淺,顯得力不從心。不過,男兒在世當立志,今天就先從 Spring IOC 容器的初始化開始說起,即使完成不了對整個 Spring 框架的完全掌握,也不丟人,因為小編動手了,穩住,咱能贏!

下面說一些閱讀前的建議:

1、閱讀源碼分析是非常無聊的,但既然你進來了,肯定也是對這個東西進行了解,也希望這篇總結能對你有所啟發。

2、前方高能,文章可能會非常的長,圖文并茂。

3、閱讀前建議你對相關設計模式、軟件設計 6 大原則有所了解,小編會在行文中進行穿插。

4、如果你發現文章觀點有所錯誤或者與你見解有差異,歡迎指出和交流!

5、建議你邊看文章的時候可以邊在 IDE 中進行調試跟蹤

6、文章所有 UML 圖利用 idea 自動生成,具體生成方法為:選中一個類名,先ctrl+shift+alt+U,再ctrl+alt+B,然后回車即可

二、文章將圍繞什么來進行展開?

不多,就一行代碼,如下圖:

這句是 Spring 初始化的代碼,雖然只有一句代碼,但內容賊多!

三、Spring 容器 IOC 有哪些東西組成?

這樣子,小編先理清下思路,一步一步來:

1、上面那句代碼有個文件叫applicationContext.xml, 這是個資源文件,由于我們的bean都在里邊進行配置定義,那 Spring 總得對這個文件進行讀取并解析吧!所以 Spring 中有個模塊叫Resource模塊,顧名思義,就是資源嘛!用于對所有資源xml、txt、property等文件資源的抽象。

下面先貼一張小編生成的類圖(圖片有點大,不知道會不會不清晰,如果不清晰可以按照上面說的idea生成方法去生成即可):

可以看到Resource是整個體系的根接口,點進源碼可以看到它定義了許多的策略方法,因為它是用了策略模式這種設計模式,運用的好處就是策略接口/類定義了同一的策略,不同的子類有不同的具體策略實現,客戶端調用時傳入一個具體的實現對象比如UrlResource或者FileSystemResource給策略接口/類Resource即可!

所有策略如下:

2、上面講了 Spring 框架對各種資源的抽象采用了策略模式,那么問題來了,現在表示資源的東西有了,那么是怎么把該資源加載進來呢?于是就有了下面的ResourceLoader組件,該組件負責對 Spring 資源的加載,資源指的是xml、properties等文件資源,返回一個對應類型的Resource對象。。UML 圖如下:

從上面的 UML 圖可以看出,ResourceLoader組件其實跟Resource組件差不多,都是一個根接口,對應有不同的子類實現,比如加載來自文件系統的資源,則可以使用FileSystemResourceLoader, 加載來自ServletContext上下文的資源,則可以使用ServletContextResourceLoader。還有最重要的一點。

從上圖看出,ApplicationContext,AbstractApplication是實現了ResourceLoader的,這說明什么呢?說明我們的應用上下文ApplicationContext擁有加載資源的能力,這也說明了為什么可以通過傳入一個String resource path給ClassPathXmlApplicationContext("applicationContext.xml")就能獲得 xml 文件資源的原因了!清晰了嗎?nice!

3、上面兩點講到了,好!既然我們擁有了加載器ResourceLoader,也擁有了對資源的描述Resource, 但是我們在 xml 文件中聲明的標簽在 Spring 又是怎么表示的呢?

注意這里只是說對bean的定義,而不是說如何將轉換為bean對象。我想應該不難理解吧!就像你想表示一個學生Student,那么你在程序中肯定要聲明一個類Student吧!

至于學生數據是從excel導入,或者程序運行時new出來,或者從xml中加載進來這些都不重要,重要的是你要有一個將現實中的實體表示為程序中的對象的東西,所以也需要在 Spring 中做一個定義!于是就引入一個叫BeanDefinition的組件,UML 圖如下:

下面講解下 UML 圖:

首先配置文件中的標簽跟我們的BeanDefinition是一一對應的,元素標簽擁有class、scope、lazy-init等配置屬性,BeanDefinition則提供了相應的beanClass、scope、lazyInit屬性。

4、有了加載器ResourceLoader,也擁有了對資源的描述Resource,也有了對bean的定義,我們不禁要問,我們的Resource資源是怎么轉成我們的BeanDefinition的呢? 因此就引入了BeanDefinitionReader組件, Reader 嘛!就是一種讀取機制,UML 圖如下:

從上面可以看出,Spring 對 reader 進行了抽象,具體的功能交給其子類去實現,不同的實現對應不同的類,如PropertiedBeanDefinitionReader,XmlBeanDefinitionReader對應從 Property 和 xml 的 Resource 解析成BeanDefinition。

5、好了!基本上所有組件都快齊全了!對了,還有一個組件,你有了BeanDefinition后,你還必須將它們注冊到工廠中去,所以當你使用getBean()方法時工廠才知道返回什么給你。

還有一個問題,既然要保存注冊這些bean, 那肯定要有個數據結構充當容器吧!沒錯,就是一個Map, 下面貼出BeanDefinitionRegistry的一個實現,叫SimpleBeanDefinitionRegistry的源碼圖:

BeanDefinitionRegistry的 UML 圖如下:

從圖中可以看出,BeanDefinitionRegistry有三個默認實現,分別是SimpleBeanDefinitionRegistry,DefaultListableBeanFactory,GenericApplicationContext, 其中SimpleBeanDefinitionRegistry,DefaultListableBeanFactory都持有一個 Map。

也就是說這兩個實現類把保存了 bean。而GenericApplicationContext則持有一個DefaultListableBeanFactory對象引用用于獲取里邊對應的 Map。在DefaultListableBeanFactory中

在GenericApplicationContext中

6、前面說的 5 個點基本上可以看出ApplicationContext上下文基本直接或間接貫穿所有的部分,因此我們一般稱之為容器,除此之外,ApplicationContext還擁有除了bean容器這種角色外,還包括了獲取整個程序運行的環境參數等信息(比如 JDK 版本,jre 等),其實這部分 Spring 也做了對應的封裝,稱之為Enviroment, 下面就跟著小編的 eclipse, 一起 debug 下容器的初始化工程吧!

四、實踐是檢驗真理的唯一標準

學生類Student.java如下:

package com.wokao666;public class Student { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } public Student() { super(); } @Override public String toString() { return "Student [id=" + id + ", ]"; }}

在application.xml中進行配置,兩個bean:

<bean id="stu1" class="com.wokao666.Student"> <property >property> <property >property> <property >property> bean> <bean id="stu2" class="com.wokao666.Student"> <property >property> <property >property> <property >property> bean>

好了,接下來給最開頭那段代碼打個斷點 (Breakpoint):

第一步:急切地加載ContextClosedEvent類,以避免在WebLogic 8.1中的應用程序關閉時出現奇怪的類加載器問題。

這一步無需太過在意!

第二步:既然是new ClassPathXmlApplicationContext()?那么就調用構造器嘛!

第三步:

第四步:

好,我們跟著第三步中的super(parent),再結合上面第三節的第 6 小點 UML 圖一步一步跟蹤,然后我們來到AbstractApplicationContext的這個方法:

那么里邊的resourcePatternResolver的類型是什么呢?屬于第三節說的 6 大步驟的哪個部分呢?通過跟蹤可以看到它的類型是ResourcePatternResolver類型的,而ResourcePatternResolver又是繼承了ResourceLoader接口,因此屬于加載資源模塊,如果還不清晰,咱們再看看ResourcePatternResolver的源碼即可,如下圖:

對吧!不僅繼承ResourceLoader接口,而且只定義一個getResources()方法用于返回Resource[]資源集合。再者,這個接口還使用了策略模式,其具體的實現都在實現類當中,好吧!來看看 UML 圖就知道了!

PathMatchingResourcePatternResolver這個實現類呢!它就是用來解釋不同路徑資源的,比如你傳入的資源路徑有可能是一個常規的url, 又或者有可能是以classpath*前綴,都交給它處理。

ServletContextResourcePatternResolver這個實現類顧名思義就是用來加載Servlet上下文的,通常用在 web 中。

第五步:

接著第四步的方法,我們在未進入第四步的方法時,此時會對AbstractApplicationContext進行實例化,此時this對象的某些屬性被初始化了(如日志對象),如下圖:

接著進入getResourcePatternResolver()方法:

第四步說了,PathMatchingResourcePatternResolver用來處理不同的資源路徑的,怎么處理,我們先進去看看!

如果找到,此時控制臺會打印找到用于OSGi包URL解析的Equinox FileLocator日志。沒打印很明顯找不到!

運行完成返回setParent()方法。

第六步:

如果父代是非null,,則該父代與當前this應用上下文環境合并。顯然這一步并沒有做什么事!parent顯然是null的,那么就不合并嘛!還是使用當前this的環境。

做個總結:前六步基本上做了兩件事:

  • 1、初始化相關上下文環境,也就是初始化ClassPathXmlApplicationContext實例

  • 2、獲得一個resourcePatternResolver對象,方便第七步的資源解析成Resource對象

第七步:

第七步又回到剛開始第三步的代碼,因為我們前面 6 步已經完成對super(parent)的追蹤。讓我們看看setConfigLocation()方法是怎么一回事~

/** * Set the config locations for this application context.//未應用上下文設置資源路徑 *

If not set, the implementation may use a default as appropriate.//如果未設置,則實現可以根據需要使用默認值。

*/public void setConfigLocations(String... locations) { if (locations != null) {//非空 Assert.noNullElements(locations, "Config locations must not be null");//斷言保證locations的每個元素都不為null this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i++) { this.configLocations[i] = resolvePath(locations[i]).trim();//去空格,很好奇resolvePath做了什么事情? } } else { this.configLocations = null; }}

進入resolvePath()方法看看:

/** * 解析給定的資源路徑,必要時用相應的環境屬性值替換占位符,應用于資源路徑配置。 * Resolve the given path, replacing placeholders with corresponding * environment property values if necessary. Applied to config locations. * @param path the original file path * @return the resolved file path * @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String) */protected String resolvePath(String path) { return getEnvironment().resolveRequiredPlaceholders(path);}進入getEnvironment()看看:/** * {@inheritDoc} *

If {@code null}, a new environment will be initialized via

* {@link #createEnvironment()}. */@Overridepublic ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = createEnvironment(); } return this.environment;}

進入createEnvironment(), 方法,我們看到在這里創建了一個新的StandardEnviroment對象,它是Environment的實現類,表示容器運行的環境,比如 JDK 環境,Servlet 環境,Spring 環境等等。

每個環境都有自己的配置數據,如System.getProperties()、System.getenv()等可以拿到 JDK 環境數據;ServletContext.getInitParameter()可以拿到 Servlet 環境配置數據等等, 也就是說 Spring 抽象了一個Environment來表示環境配置。

生成的StandardEnviroment對象并沒有包含什么內容,只是一個標準的環境,所有的屬性都是默認值。

第八步:這一步是重頭戲

先做個小結:到現在為止,我們擁有了以下實例:

現在代碼運行到如下圖的refresh()方法:

看一下這個方法的內容是什么?

@Overridepublic void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 刷新前準備工作,包括設置啟動時間,是否激活標識位,初始化屬性源(property source)配置 prepareRefresh(); // 創建beanFactory(過程是根據xml為每個bean生成BeanDefinition并注冊到生成的beanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //準備創建好的beanFactory(給beanFactory設置ClassLoader,設置SpEL表達式解析器,設置類型轉化器【能將xml String類型轉成相應對象】, //增加內置ApplicationContextAwareProcessor對象,忽略各種Aware對象,注冊各種內置的對賬對象【BeanFactory,ApplicationContext】等, //注冊AOP相關的一些東西,注冊環境相關的一些bean prepareBeanFactory(beanFactory); try { // 模板方法,為容器某些子類擴展功能所用(工廠后處理器)這里可以參考BeanFactoryPostProcessor接口的postProcessBeanFactory方法 postProcessBeanFactory(beanFactory); // 調用所有BeanFactoryPostProcessor注冊為Bean invokeBeanFactoryPostProcessors(beanFactory); // 注冊所有實現了BeanPostProcessor接口的Bean registerBeanPostProcessors(beanFactory); // 初始化MessageSource,和國際化相關 initMessageSource(); // 初始化容器事件傳播器 initApplicationEventMulticaster(); // 調用容器子類某些特殊Bean的初始化,模板方法 onRefresh(); // 為事件傳播器注冊監聽器 registerListeners(); // 初始化所有剩余的bean(普通bean) finishBeanFactoryInitialization(beanFactory); // 初始化容器的生命周期事件處理器,并發布容器的生命周期事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 銷毀已創建的bean destroyBeans(); // 重置`active`標志 cancelRefresh(ex); throw ex; } finally { //重置一些緩存 resetCommonCaches(); } }}

在這里我想說一下,這個refresh()方法其實是一個模板方法, 很多方法都讓不同的實現類去實現,但該類本身也實現了其中一些方法,并且這些已經實現的方法是不允許子類重寫的,比如:prepareRefresh()方法。更多模板方法設計模式,可看我之前的文章?談一談我對‘模板方法’設計模式的理解(Template)。

先進入prepareRefresh()方法:

/** * Prepare this context for refreshing, setting its startup date and * active flag as well as performing any initialization of property sources. */protected void prepareRefresh() { this.startupDate = System.currentTimeMillis();//設置容器啟動時間 this.closed.set(false);//容器關閉標志,是否關閉? this.active.set(true);//容器激活標志,是否激活? if (logger.isInfoEnabled()) {//運行到這里,控制臺就會打印當前容器的信息 logger.info("Refreshing " + this); } // 空方法,由子類覆蓋實現,初始化容器上下文中的property文件 initPropertySources(); //驗證標記為必需的所有屬性均可解析,請參閱ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); //允許收集早期的ApplicationEvents,一旦多播器可用,即可發布... this.earlyApplicationEvents = new LinkedHashSet();}

控制臺輸出:

三月 22, 2018 4:21:13 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@96532d6: startup date [Thu Mar 22 16:21:09 CST 2018]; root of context hierarchy

第九步:

進入obtainFreshBeanFactory()方法:

/** * 告訴子類刷新內部bean工廠(子類是指AbstractApplicationContext的子類,我們使用的是ClassPathXmlApplicationContext) * Tell the subclass to refresh the internal bean factory. */protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory();//刷新Bean工廠,如果已經存在Bean工廠,那就關閉并銷毀,再創建一個新的bean工廠 ConfigurableListableBeanFactory beanFactory = getBeanFactory();//獲取新創建的Bean工廠 if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);//控制臺打印 } return beanFactory;}進入refreshBeanFactory()方法:/** * 該實現執行該上下文的基礎Bean工廠的實際刷新,關閉以前的Bean工廠(如果有的話)以及為該上下文的生命周期的下一階段初始化新鮮的Bean工廠。 * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. */@Overrideprotected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) {//如果已有bean工廠 destroyBeans();//銷毀 closeBeanFactory();//關閉 } try { DefaultListableBeanFactory beanFactory = createBeanFactory();//創建一個新的bean工廠 beanFactory.setSerializationId(getId());//為序列化目的指定一個id,如果需要,可以將此BeanFactory從此id反序列化回BeanFactory對象。 //定制容器,設置啟動參數(bean可覆蓋、循環引用),開啟注解自動裝配 customizeBeanFactory(beanFactory); 將所有BeanDefinition載入beanFactory中,此處依舊是模板方法,具體由子類實現 loadBeanDefinitions(beanFactory); //beanFactory同步賦值 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); }}

總結:這一步主要的工作就是判斷刷新容器前是否已經有 beanfactory 存在,如果有,那么就銷毀舊的 beanfactory, 那么就銷毀掉并且創建一個新的 beanfactory 返回給容器,同時將 xml 文件的BeanDefinition注冊到 beanfactory 中。如果不太清楚可以回過頭看看我們的第三節第5點內容

第十步:

進入第九步的loadBeanDefinitions(beanFactory)方法中去take a look:

/** * 使用XmlBeanDefinitionReader來加載beandefnition,之前說過使用reader機制加載Resource資源變為BeanDefinition對象 * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 創建XmlBeanDefinitionReader對象 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 使用當前上下文Enviroment中的Resource配置beanDefinitionReader,因為beanDefinitionReader要將Resource解析成BeanDefinition嘛! beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //初始化這個reader initBeanDefinitionReader(beanDefinitionReader); //將beandefinition注冊到工廠中(這一步就是將bean保存到Map中) loadBeanDefinitions(beanDefinitionReader);}

控制臺輸出:

三月 22, 2018 5:09:40 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [applicationContext.xml]

第十一步:

進入prepareBeanFactory(beanFactory)方法:

//設置bean類加載器//設置Spring語言表達式(SpEL)解析器//掃描ApplicationContextAware bean//注冊類加載期類型切面織入(AOP)LoadTimeWeaver//為各種加載進入beanFactory的bean配置默認環境

第十二步:

postProcessBeanFactory(beanFactory)方法:

postProcessBeanFactory同樣作為一個模板方法,由子類來提供具體的實現,子類可以有自己的特殊對BeanDefinition后處理方法,即子類可以在這對前面生成的BeanDefinition,即bean的元數據再處理。比如修改某個bean的id/name屬性、scope屬性、lazy-init屬性等。

第十三步:

invokeBeanFactoryPostProcessors(beanFactory)方法:

該方法調用所有的BeanFactoryPostProcessor,它是一個接口,實現了此接口的類需重寫postProcessBeanFactory()這個方法,可以看出該方法跟第十二步的方法是一樣的,只不過作為接口,更多的是提供給開發者來對生成的BeanDefinition做處理,由開發者提供處理邏輯。

第十四步:

其余剩下的方法基本都是像初始化消息處理源,初始化容器事件,注冊bean監聽器到事件傳播器上,最后完成容器刷新。

五、總結

恭喜我,我終于寫完了,同樣也恭喜你,你也閱讀完了。

我很佩服我自己能花這么長時間進行總結發布,之所以要進行總結,那是因為小編還是贊同好記性不如爛筆頭的說法。

你不記,你過陣子就會忘記,你若記錄,你過陣子也會忘記!區別在于忘記了,可以回過頭在很短的時間內進行回憶,查漏補缺,減少學習成本。

再者,我認為我分析的還不是完美的,缺陷很多,因此我將我寫的所有文章發布出來和大家探討交流,汕頭大學有校訓說得非常地好,那就是說知識是用來共享的,因為共享了,知識才能承前啟后。

現在再梳理一下 Spring 初始化過程:

1、首先初始化上下文,生成ClassPathXmlApplicationContext對象,在獲取resourcePatternResolver對象將xml解析成Resource對象。

2、利用 1 生成的 context、resource 初始化工廠,并將 resource 解析成 beandefinition, 再將 beandefinition 注冊到 beanfactory 中。

推薦閱讀

1、Spring Boot+Vue項目實戰

2、B站:4小時上手MyBatis Plus

3、一文搞懂前后端分離

4、快速上手Spring Boot+Vue前后端分離

楠哥簡介

資深 Java 工程師,微信號?southwindss

《Java零基礎實戰》一書作者

騰訊課程官方 Java 面試官,今日頭條認證大V

GitChat認證作者,B站認證UP主(楠哥教你學Java)

致力于幫助萬千 Java 學習者持續成長。

有收獲,就在看

總結

以上是生活随笔為你收集整理的spring图片转视频_一直在用的 Spring,你知道它的加载原理吗?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。