Java 自定義Spring框架與Spring IoC相關(guān)接口分析
在本講,我們來(lái)對(duì)Spring IoC功能相關(guān)的接口逐一進(jìn)行分析,分析這些接口的原因就是為了我們自己定義Spring IoC功能提前做好準(zhǔn)備。
Spring IoC相關(guān)接口分析
BeanFactory接口解析
對(duì)于BeanFactory接口,我之前只是稍微提到過(guò),并且將就著用了一下它。這里,我將會(huì)對(duì)BeanFactory接口進(jìn)行一個(gè)具體講解。
Spring中bean的創(chuàng)建是典型的工廠模式,這一系列的bean工廠,即IoC容器,為開(kāi)發(fā)者管理對(duì)象之間的依賴(lài)關(guān)系提供了很多便利和基礎(chǔ)服務(wù),在Spring中有許多IoC容器的實(shí)現(xiàn)可供用戶(hù)選擇,其相互關(guān)系如下圖所示。
這里說(shuō)到了Spring中bean的創(chuàng)建是典型的工廠模式,那么你知道到底是哪種工廠模式嗎?其實(shí),這里面用的是簡(jiǎn)單工廠+配置文件的形式,相信大家都知道簡(jiǎn)單工廠+配置文件會(huì)大大降低對(duì)象和對(duì)象之間的耦合。
上面還說(shuō)到了在Spring中有許多IoC容器的實(shí)現(xiàn)可供用戶(hù)選擇,這句話怎么理解呢?我們?cè)趧?chuàng)建IoC容器時(shí),創(chuàng)建的肯定是BeanFactory接口的子實(shí)現(xiàn)類(lèi)對(duì)象,那么我們就要想了,到底有哪些子實(shí)現(xiàn)類(lèi)可供咱選擇呢?嘿嘿!這不用你操心,因?yàn)镾pring提供了很多該接口的子實(shí)現(xiàn)類(lèi)供我們?nèi)ミx擇。
從以上類(lèi)圖中可以看到,BeanFactory作為最頂層的一個(gè)接口,定義了IoC容器的基本功能規(guī)范,而且BeanFactory有三個(gè)重要的子接口,分別是ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。但是從類(lèi)圖中我們可以發(fā)現(xiàn)最終的默認(rèn)實(shí)現(xiàn)類(lèi)是DefaultListableBeanFactory,它實(shí)現(xiàn)了所有的接口,這就意味著如果我們想要用的話,那么直接用該子實(shí)現(xiàn)類(lèi)就行了!
看完上面這段話,有兩點(diǎn)需要引起我們的注意,一是BeanFactory作為最頂層的一個(gè)接口,定義了IoC容器的基本功能規(guī)范,那么到底它定義了哪些最基本的功能規(guī)范呢?其實(shí),大家想一想就知道了,工廠本身就是用來(lái)生產(chǎn)對(duì)象的,那么在Spring里面,bean工廠生產(chǎn)的就是bean對(duì)象了,所以BeanFactory里面肯定是要提供獲取bean對(duì)象的方法的,這個(gè)我后面就會(huì)詳細(xì)地講到;二是BeanFactory屬于延時(shí)加載,也就是說(shuō)對(duì)于bean對(duì)象Spring進(jìn)行了一個(gè)延時(shí)加載。
問(wèn)題來(lái)了,為何要定義這么多層次的接口呢?定義的少一點(diǎn),整個(gè)架構(gòu)看起來(lái)不就更加簡(jiǎn)單嗎?原因如下:
每個(gè)接口都有它的使用場(chǎng)合,主要是為了區(qū)分在Spring內(nèi)部操作過(guò)程中對(duì)象的傳遞和轉(zhuǎn)化,對(duì)對(duì)象的數(shù)據(jù)訪問(wèn)所做的限制。例如,
- ListableBeanFactory接口:表示bean可列表化。什么意思???我給大家解釋解釋?zhuān)f(shuō)的是該接口可以通過(guò)列表的方式對(duì)bean對(duì)象進(jìn)行一個(gè)存儲(chǔ)。
- HierarchicalBeanFactory接口:表示bean是有繼承關(guān)系的,也就是每個(gè)bean可能有父bean。
- AutowireCapableBeanFactory接口:定義bean的自動(dòng)裝配規(guī)則。依賴(lài)注入就屬于自動(dòng)裝配規(guī)則里面的。
以上這三個(gè)接口共同定義了bean的集合、bean之間的關(guān)系及bean的行為。不過(guò),最基本的IoC容器接口還是BeanFactory,下面我們就來(lái)看一下它的源碼,看它里面到底定義了哪些最基本的功能規(guī)范。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.beans.factory; import org.springframework.beans.BeansException; import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; // 根據(jù)bean的名稱(chēng)獲取IoC容器中的bean對(duì)象 Object getBean(String var1) throws BeansException; // 根據(jù)bean的名稱(chēng)獲取IoC容器中的bean對(duì)象,并指定獲取到的bean對(duì)象的類(lèi)型,這樣我們使用時(shí)就不需要進(jìn)行類(lèi)型強(qiáng)轉(zhuǎn)了 <T> T getBean(String var1, Class<T> var2) throws BeansException; Object getBean(String var1, Object... var2) throws BeansException; <T> T getBean(Class<T> var1) throws BeansException; <T> T getBean(Class<T> var1, Object... var2) throws BeansException; <T> ObjectProvider<T> getBeanProvider(Class<T> var1); <T> ObjectProvider<T> getBeanProvider(ResolvableType var1); // 判斷容器中是否包含指定名稱(chēng)的bean對(duì)象 boolean containsBean(String var1); // 根據(jù)bean的名稱(chēng)判斷是否是單例 boolean isSingleton(String var1) throws NoSuchBeanDefinitionException; boolean isPrototype(String var1) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String var1) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException; String[] getAliases(String var1); }
看到那一系列的getBean方法沒(méi),它們都是用來(lái)獲取bean對(duì)象的,當(dāng)然了,BeanFactory接口里面還定義了一些其他的基本功能規(guī)范,這里我就不再細(xì)說(shuō)了。
在BeanFactory里只對(duì)IoC容器的基本行為做了定義,根本不關(guān)心你的bean是如何定義及怎樣加載的。正如我們只關(guān)心能從工廠里得到什么產(chǎn)品,而不關(guān)心工廠是怎么生產(chǎn)這些產(chǎn)品的一樣。當(dāng)然,bean的定義以及加載是要交由給BeanFactory接口的子實(shí)現(xiàn)類(lèi)去做的。
BeanFactory有一個(gè)很重要的子接口,就是ApplicationContext接口,該接口主要是來(lái)規(guī)范容器中的bean對(duì)象是非延時(shí)加載的,即在創(chuàng)建容器對(duì)象的時(shí)候就對(duì)bean對(duì)象進(jìn)行初始化,并存儲(chǔ)到一個(gè)容器中。大家不妨來(lái)看一下下面這張圖。
可以看到最頂層就是BeanFactory接口,它下面有一個(gè)子接口叫ApplicationContext,而該子接口下面又有三個(gè)比較重要的子實(shí)現(xiàn)類(lèi),還記得上面我說(shuō)過(guò)在Spring中有許多IoC容器的實(shí)現(xiàn)可供用戶(hù)選擇嗎?這仨子實(shí)現(xiàn)類(lèi)就是。如果要想知道工廠是如何產(chǎn)生對(duì)象的,那么我們就需要查看具體的IoC容器實(shí)現(xiàn)了,Spring提供了許多IoC容器實(shí)現(xiàn),比如:
- FileSystemXmlApplicationContext:根據(jù)系統(tǒng)路徑加載XML配置文件,并創(chuàng)建IoC容器對(duì)象。
- ClassPathXmlApplicationContext:根據(jù)類(lèi)路徑加載XML配置文件,并創(chuàng)建IoC容器對(duì)象。
- AnnotationConfigApplicationContext:加載注解類(lèi)配置,并創(chuàng)建IoC容器。
注意了,我們?cè)诤竺孀约喝ザxSpring IoC功能時(shí),我們只針對(duì)ClassPathXmlApplicationContext類(lèi)來(lái)實(shí)現(xiàn),也就是只關(guān)注類(lèi)路徑下XML配置文件的解析與對(duì)應(yīng)IoC容器的創(chuàng)建。
關(guān)于BeanFactory接口的分析,我們就分析至此。
BeanDefinition接口解析
Spring IoC容器管理的是我們定義的各種bean對(duì)象及其相互關(guān)系,而bean對(duì)象在Spring實(shí)現(xiàn)中是以BeanDefinition來(lái)描述的。
來(lái)看一下下面配置文件中的bean配置,如果你用過(guò)Spring或者Spring MVC框架的話,那么相信你對(duì)這段配置肯定不會(huì)陌生,注意了,在<bean>
標(biāo)簽內(nèi)我們還可以設(shè)置很多屬性,例如scope、init-method、destory-method等,只是在這里我們并沒(méi)有全部列舉出來(lái)。
<bean id="userDao" class="com.meimeixia.dao.impl.UserDaoImpl"></bean>
現(xiàn)在對(duì)于Spring來(lái)說(shuō)的話,它就得解析這個(gè)<bean>
標(biāo)簽了,解析時(shí),必然就要把該<bean>
標(biāo)簽對(duì)應(yīng)的屬性的值進(jìn)行一個(gè)封裝,那Spring會(huì)封裝成什么樣的一個(gè)對(duì)象呢?會(huì)封裝成BeanDefinition對(duì)象,又由于BeanDefinition是一個(gè)接口,所以最終Spring會(huì)封裝成一個(gè)該接口的子實(shí)現(xiàn)類(lèi)對(duì)象。
接下來(lái),我們就來(lái)看看BeanDefinition接口的繼承體系,如下圖所示。
可以看到,BeanDefinition確實(shí)是一個(gè)接口,而且它下面有一個(gè)具體的子實(shí)現(xiàn)類(lèi),即RootBeanDefinition。
BeanDefinitionReader接口解析
剛才我們講解完了BeanDefinition接口,知道了該接口的作用就是對(duì)XML配置文件里面<bean>
標(biāo)簽相關(guān)的屬性進(jìn)行封裝。那么接下來(lái)我們就來(lái)思考一個(gè)問(wèn)題,就是XML配置文件到底是由誰(shuí)來(lái)解析的呢?既然提到解析了,那么我們就要來(lái)看一看BeanDefinitionReader接口了。
bean的解析過(guò)程非常復(fù)雜,功能被分得很細(xì),因?yàn)檫@里需要被擴(kuò)展的地方很多,必須保證足夠的靈活性,以應(yīng)對(duì)可能的變化。bean的解析主要就是對(duì)Spring配置文件的解析,這個(gè)解析過(guò)程主要通過(guò)BeanDefinitionReader來(lái)完成。下面我們就來(lái)看看Spring中BeanDefinitionReader的類(lèi)結(jié)構(gòu)圖,如下圖所示。
當(dāng)然了,你也可以回到IDEA里面去查看一下BeanDefinitionReader接口的繼承體系,如下圖所示。
可以看到,BeanDefinitionReader接口有三個(gè)子實(shí)現(xiàn)類(lèi),這里我只講一下上面紅框框住的兩個(gè)子實(shí)現(xiàn)類(lèi)。
- PropertiesBeanDefinitionReader:主要解析properties格式的配置文件。但是,在實(shí)際開(kāi)發(fā)中,你會(huì)發(fā)現(xiàn)很少會(huì)用到properties格式的配置文件,用的更多的是XML格式的配置文件。
- XmlBeanDefinitionReader:主要解析XML格式的配置文件。
BeanDefinitionReader既然是一個(gè)接口的話,那么它里面定義的便是最基本的功能規(guī)范,這些規(guī)范針對(duì)不同的子實(shí)現(xiàn)類(lèi)會(huì)有不同的實(shí)現(xiàn),從上圖中我們也看到了BeanDefinitionReader接口確實(shí)是有不同的子實(shí)現(xiàn)類(lèi)。這些子實(shí)現(xiàn)類(lèi)會(huì)來(lái)決定到底解析什么樣的配置文件,究竟是properties格式的呢,還是XML格式的,所以你會(huì)發(fā)現(xiàn)Spring底層設(shè)計(jì)的還是比較全面的。
接下來(lái),我們就來(lái)看一下BeanDefinitionReader接口的源碼,看它里面到底定義了哪些最基本的功能規(guī)范。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.beans.factory.support; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.lang.Nullable; public interface BeanDefinitionReader { // 獲取BeanDefinitionRegistry注冊(cè)器對(duì)象 BeanDefinitionRegistry getRegistry(); @Nullable ResourceLoader getResourceLoader(); @Nullable ClassLoader getBeanClassLoader(); BeanNameGenerator getBeanNameGenerator(); /* * 下面這些重載的loadBeanDefinitions方法都是從指定的資源中加載bean定義 */ int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException; int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException; int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException; int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException; }
可以看到,BeanDefinitionReader接口里面定義了很多很多的方法,不過(guò)我們重點(diǎn)關(guān)注兩類(lèi)方法:
- getRegistry方法:獲取BeanDefinitionRegistry注冊(cè)器對(duì)象。
- loadBeanDefinitions方法:從不同指定的資源中加載bean定義,也就是加載配置文件。
我相信,從BeanDefinitionReader接口定義的功能中你已經(jīng)理解了它具體的一個(gè)作用。
BeanDefinitionRegistry接口解析
接下來(lái),我們來(lái)分析一下BeanDefinitionRegistry接口。其實(shí),剛才我們?cè)谌シ治鯞eanDefinitionReader接口的時(shí)候就見(jiàn)過(guò),還記得嗎?BeanDefinitionReader接口里面的getRegistry方法的返回值類(lèi)型就是BeanDefinitionRegistry。
我們都知道,BeanDefinitionReader是用來(lái)解析bean定義,并將其(指的就是bean定義)封裝成BeanDefinition對(duì)象的。還有,我想大家也知道我們定義的配置文件中會(huì)定義很多bean標(biāo)簽,那么這里就存在一個(gè)問(wèn)題了,就是解析出來(lái)的BeanDefinition對(duì)象到底存儲(chǔ)到哪兒了呢?答案就是BeanDefinition的注冊(cè)中心,而該注冊(cè)中心頂層接口就是BeanDefinitionRegistry。
接下來(lái),我們就來(lái)看一下BeanDefinitionRegistry接口的源碼,看它里面到底定義了哪些最基本的功能規(guī)范。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.beans.factory.support; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.core.AliasRegistry; public interface BeanDefinitionRegistry extends AliasRegistry { // 往注冊(cè)表中注冊(cè)bean void registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException; // 從注冊(cè)表中刪除指定名稱(chēng)的bean void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException; // 獲取注冊(cè)表中指定名稱(chēng)的bean BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException; // 判斷注冊(cè)表中是否已經(jīng)注冊(cè)了指定名稱(chēng)的bean boolean containsBeanDefinition(String var1); // 獲取注冊(cè)表中所有的bean的名稱(chēng) String[] getBeanDefinitionNames(); int getBeanDefinitionCount(); boolean isBeanNameInUse(String var1); }
以上就是注冊(cè)中心頂層接口BeanDefinitionRegistry里面定義的最基本的功能規(guī)范。
由于BeanDefinitionRegistry是一個(gè)接口,所以我們?cè)谑褂玫臅r(shí)候肯定就是使用它的子實(shí)現(xiàn)類(lèi)了。接下來(lái),我們就來(lái)看一下Spring中BeanDefinitionRegistry的類(lèi)結(jié)構(gòu)圖,如下圖所示。
當(dāng)然了,你也可以回到IDEA里面去查看一下BeanDefinitionRegistry接口的繼承體系,如下圖所示。
從上面可以看到BeanDefinitionRegistry接口的子實(shí)現(xiàn)類(lèi)主要有以下幾個(gè):
- SimpleBeanDefinitionRegistry
從名字上來(lái)看,它就是一個(gè)簡(jiǎn)單的BeanDefinition的注冊(cè)中心,由于解析出來(lái)的BeanDefinition對(duì)象就存儲(chǔ)在BeanDefinition的注冊(cè)中心,所以它必然是一個(gè)容器。在這里我要給大家提個(gè)醒,相比另外兩個(gè)類(lèi),該類(lèi)是我們要更加要關(guān)注的。
接下來(lái),我們就要看看該類(lèi)里面有沒(méi)有定義什么容器來(lái)存儲(chǔ)BeanDefinition對(duì)象了。查看該類(lèi)的源碼,如下圖所示,你會(huì)發(fā)現(xiàn)在其成員位置處定義了一個(gè)Map集合,而且Map集合的鍵是String類(lèi)型的,值是BeanDefinition類(lèi)型的。其實(shí),從這里就可以看出,該Map集合就是用來(lái)注冊(cè)BeanDefinition對(duì)象的,其中,鍵就是要注冊(cè)的BeanDefinition對(duì)象的名稱(chēng),值就是要注冊(cè)的BeanDefinition對(duì)象,不知我這樣說(shuō),大家明白了沒(méi)?
- DefaultListableBeanFactory
該類(lèi)我們?cè)诜治鯞eanFactory接口的時(shí)候就見(jiàn)過(guò),還記得嗎?不記得的話,再回頭去看一下BeanFactory的類(lèi)結(jié)構(gòu)圖。你會(huì)發(fā)現(xiàn)該類(lèi)不僅實(shí)現(xiàn)了BeanFactory接口,還實(shí)現(xiàn)了BeanDefinitionRegistry接口,所以該類(lèi)既是容器,也是注冊(cè)表。
接下來(lái),我們也是要看看該類(lèi)里面有沒(méi)有定義什么容器來(lái)存儲(chǔ)BeanDefinition對(duì)象。查看該類(lèi)的源碼,如下圖所示,你會(huì)發(fā)現(xiàn)在其成員位置處也定義了一個(gè)Map集合來(lái)注冊(cè)BeanDefinition對(duì)象。
- GenericApplicationContext
該類(lèi)間接地實(shí)現(xiàn)了ApplicationContext接口,這點(diǎn)你通過(guò)查閱源碼就能知道了,所以該類(lèi)同上,既是容器,也是注冊(cè)表。
創(chuàng)建容器
剛才我們分析了一下與Spring IoC功能相關(guān)的一些接口,分析完這些接口之后,大家要明確的就是每一個(gè)接口,它的作用是什么,以及該接口下面比較常用的子實(shí)現(xiàn)類(lèi)有哪些。
明確了之后,接下來(lái)我們?cè)賮?lái)分析一個(gè)問(wèn)題,就是創(chuàng)建容器的時(shí)候,到底做了些什么事?
我們都知道BeanFactory是Spring IoC容器最頂層的一個(gè)接口,但咱們現(xiàn)在寫(xiě)的程序用的卻是ApplicationContext這個(gè)子接口及其下面的ClassPathXmlApplicationContext子實(shí)現(xiàn)類(lèi),這是為什么呢?我不說(shuō),想必大家也知道,無(wú)非就是ApplicationContext屬于非延時(shí)加載,也就是說(shuō)在創(chuàng)建容器對(duì)象的時(shí)候,就會(huì)去實(shí)例化bean對(duì)象,并存儲(chǔ)在容器里面了。
下面我們就以ClassPathXmlApplicationContext這個(gè)容器類(lèi)來(lái)分析一下創(chuàng)建容器的時(shí)候,到底都做了些什么事。
首先,查看一下ClassPathXmlApplicationContext類(lèi)的源碼,如下圖所示,可以看到它里面提供了很多構(gòu)造方法,有無(wú)參的,有有參的,反正是有很多,三歲小孩都知道當(dāng)我們?nèi)?chuàng)建這個(gè)類(lèi)的對(duì)象時(shí),必然是要調(diào)用它里面的構(gòu)造方法的。
然后,我們就來(lái)看一下咱們平時(shí)調(diào)用的有參構(gòu)造到底做了哪些事情。你會(huì)發(fā)現(xiàn)該有參構(gòu)造又調(diào)用了另外一個(gè)有參構(gòu)造,那這個(gè)有參構(gòu)造又是誰(shuí)呢?看,是它!
可以看到,在這個(gè)構(gòu)造方法里面會(huì)先判斷refresh變量是否為true,若為true則調(diào)用refresh方法。很顯然,該refresh變量的值就是true,因?yàn)閺纳弦粋€(gè)有參構(gòu)造跳轉(zhuǎn)到該有參構(gòu)造時(shí),第二個(gè)參數(shù)傳遞的就是true。既然refresh變量的值為true,那么肯定就會(huì)去調(diào)用refresh方法。
那么,refresh方法又做了些什么呢?點(diǎn)擊進(jìn)入該方法去看看不就得了,你會(huì)發(fā)現(xiàn)此時(shí)跳轉(zhuǎn)到父類(lèi)中了,如下圖所示。
可以看到,該refresh方法做了很多很多事情,這里我就做一個(gè)簡(jiǎn)短說(shuō)明,refresh方法做的事就是加載配置文件并去初始化bean對(duì)象,然后將bean對(duì)象存儲(chǔ)在容器里面。注意,該方法的具體源代碼,我們就不逐行去分析了,后續(xù)我們自己去實(shí)現(xiàn)Spring IoC功能時(shí),再詳細(xì)的去說(shuō)一下它底層的一個(gè)實(shí)現(xiàn)。
最后,我給大家做個(gè)總結(jié)吧!也不知道大家看不看得懂。
ClassPathXmlApplicationContext對(duì)bean配置資源的載入是從refresh方法開(kāi)始的。refresh方法是一個(gè)模板方法,規(guī)定了IoC容器的啟動(dòng)流程,因?yàn)橛行┻壿嬍且唤o其子類(lèi)去實(shí)現(xiàn)的。那它是如何對(duì)bean配置資源進(jìn)行載入的呢?ClassPathXmlApplicationContext通過(guò)調(diào)用其父類(lèi)AbstractApplicationContext的refresh方法啟動(dòng)整個(gè)IoC容器對(duì)bean定義的載入過(guò)程。
到此這篇關(guān)于Java 自定義Spring框架與Spring IoC相關(guān)接口分析的文章就介紹到這了,更多相關(guān)Java 自定義Spring框架內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java利用Redis實(shí)現(xiàn)高并發(fā)計(jì)數(shù)器的示例代碼
這篇文章主要介紹了Java利用Redis實(shí)現(xiàn)高并發(fā)計(jì)數(shù)器的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Java中使用Closeable接口自動(dòng)關(guān)閉資源詳解
這篇文章主要介紹了Java中使用Closeable接口自動(dòng)關(guān)閉資源詳解,Closeable接口繼承于AutoCloseable,主要的作用就是自動(dòng)的關(guān)閉資源,其中close()方法是關(guān)閉流并且釋放與其相關(guān)的任何方法,如果流已被關(guān)閉,那么調(diào)用此方法沒(méi)有效果,需要的朋友可以參考下2023-12-12關(guān)于Java中數(shù)組切片的幾種方法(獲取數(shù)組元素)
這篇文章主要介紹了關(guān)于Java中數(shù)組切片的幾種方法(獲取數(shù)組元素),切片是數(shù)組的一個(gè)引用,因此切片是引用類(lèi)型,在進(jìn)行傳遞時(shí),遵守引用傳遞的機(jī)制,需要的朋友可以參考下2023-05-05IDEA Maven依賴(lài)下載總是失敗的幾種解決方法
我們本地使用 IDEA 運(yùn)行 maven 項(xiàng)目的時(shí)候,有時(shí)候運(yùn)氣不好,就會(huì)遇到某些 maven 依賴(lài)無(wú)法正常找到、導(dǎo)入,這就會(huì)導(dǎo)致 IDEA 構(gòu)建項(xiàng)目的時(shí)候爆出一堆醒目的紅色 Error,今天給大家分享IDEA Maven依賴(lài)下載總是失敗的幾種解決方法,感興趣的朋友一起看看吧2023-09-09Java Iterator迭代器與foreach循環(huán)代碼解析
這篇文章主要介紹了Java-Iterator迭代器與foreach循環(huán),主要包括Iterator迭代器接口的操作方法和foreach 循環(huán)語(yǔ)法解析,需要的朋友可以參考下2022-04-04Java lambda list轉(zhuǎn)換map時(shí),把多個(gè)參數(shù)拼接作為key操作
這篇文章主要介紹了Java lambda list轉(zhuǎn)換map時(shí),把多個(gè)參數(shù)拼接作為key操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08關(guān)于Spring統(tǒng)一異常處理及說(shuō)明
這篇文章主要介紹了關(guān)于Spring統(tǒng)一異常處理及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09springboot?靜態(tài)方法中使用@Autowired注入方式
這篇文章主要介紹了springboot?靜態(tài)方法中使用@Autowired注入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02