- N +

bean實例化和初始化的區別?java類初始化和實例化

大家好,今天來為大家分享bean實例化和初始化的區別的一些知識點,和java類初始化和實例化的問題解析,大家要是都明白,那么可以忽略,如果不太清楚的話可以看看本篇文章,相信很大概率可以解決您的問題,接下來我們就一起來看看吧!

該如何學習spring源碼以及解析bean定義的注冊

如何學習spring源碼前言

本文屬于spring源碼解析的系列文章之一,文章主要是介紹如何學習spring的源碼,希望能夠最大限度的幫助到有需要的人。文章總體難度不大,但比較繁重,學習時一定要耐住性子堅持下去。

獲取源碼

源碼的獲取有多種途徑

GitHub

spring-framework

spring-wiki

可以從GitHub上獲取源代碼,然后自行編譯

maven

使用過maven的都知道可以通過maven下載相關的源代碼和相關文檔,簡單方便。

這里推薦通過maven的方式構建一個web項目。通過對實際項目的運行過程中進行調試來學習更好。

如何開始學習前置條件

如果想要開始學習spring的源碼,首先要求本身對spring框架的使用基本了解。明白spring中的一些特性如ioc等。了解spring中各個模塊的作用。

確定目標

首先我們要知道spring框架本身經過多年的發展現在已經是一個龐大的家族。可能其中一個功能的實現依賴于多個模塊多個類的相互配合,這樣會導致我們在閱讀代碼時難度極大。多個類之間進行跳躍很容易讓我們暈頭轉向。

所以在閱讀spring的源代碼的時候不能像在JDK代碼時一行一行的去理解代碼,需要把有限的精力更多的分配給重要的地方。而且我們也沒有必要這樣去閱讀。

在閱讀spring某一功能的代碼時應當從一個上帝視角來總覽全局。只需要知道某一個功能的實現流程即可,而且幸運的是spring的代碼規范較好,大多數方法基本都能見名知意,這樣也省去了我們很多的麻煩。

利用好工具

閱讀代碼最好在idea或者eclipse中進行,這類IDE提供的很多功能很有幫助。

在閱讀時配合spring文檔更好(如果是自行編譯源碼直接看注釋更好)。

筆記和復習

這個過程及其重要,我以前也看過一些spring的源碼,但是好幾次都是感覺比較吃力在看過一些后就放棄了。而由于沒有做筆記和沒有復習的原因很快就忘了。下次想看的時候還要重新看一遍,非常的浪費時間。

下面以IOC為例說明下我是怎么看的,供參考。

IOC入口:ApplicationContext

在研究源碼時首先要找到一個入口,這個入口怎么選擇可以自己定,當一定要和你需要看的模塊有關聯。

比如在IOC中,首先我們想到創建容器是在什么過程?

在程序啟動的時候就創建了,而且在啟動過程中大多數的bean實例就被注入了。

那問題來了,在啟動的時候是從那個類開始的呢?熟悉spring的應該都知道我們平時在做單元測試時如果要獲取bean實例,一個是通過注解,另外我們還可以通過構建一個ApplicationContext來獲?。?/p>

在實例化ApplicationContext后既可以獲取bean,那么實例化的這個過程就相當于啟動的過程了,所以我們可以將ApplicationContext當成我們的入口。

ApplicationContext是什么

首先我們要明白的事我們平時一直說的IOC容器在Spring中實際上指的就是。

如果有看過我之前手寫Spring系列文章的同學肯定知道在當時文章中充當ioc容器的是BeanFactory,每當有bean需要注入時都是由BeanFactory保存,取bean實例時也是從BeanFactory中獲取。

那為什么現在要說ApplicationContext才是IOC容器呢?

因為在spring中BeanFactory實際上是被隱藏了的。ApplicationContext是對BeanFactory的一個封裝,也提供了獲取bean實例等功能。因為BeanFactory本身的能力實在太強,如果可以讓我們隨便使用可能會對spring功能的運行造成破壞。于是就封裝了一個提供查詢ioc容器內容的ApplicationContext供我們使用。

如果項目中需要用到ApplicationContext,可以直接使用spring提供的注解獲取:

如何使用ApplicationContext

如果我們要使用ApplicationContext可以通過new該類的一個實例即可,定義好相應的xml文件。然后通過下面的代碼即可:

ApplicationContext的體系

了解一個類,首先可以來看看它的繼承關系來了解其先天的提供哪些功能。然后在看其本身又實現了哪些功能。

上圖中繼承關系從左至右簡要介紹其功能。

ApplicationEventPublisher:提供發布監聽事件的功能,接收一個監聽事件實體作為參數。需要了解的可以通過這篇文章:事件監聽ResourcePatternResolver:用于解析一些傳入的文件路徑(比如ant風格的路徑),然后將文件加載為resource。HierarchicalBeanFactory:提供父子容器關系,保證子容器能訪問父容器,父容器無法訪問子容器。ListableBeanFactory:繼承自BeanFactory,提供訪問IOC容器的方法。EnvironmentCapable:獲取環境變量相關的內容。MessageSource:提供國際化的message的解析

配置文件的加載

Spring中每一個功能都是很大的一個工程,所以在閱讀時也要分為多個模塊來理解。要理解IOC容器,我們首先需要了解spring是如何加載配置文件的。

縱覽大局

idea或者eclipse提供了一個很好的功能就是能在調試模式下看到整個流程的調用鏈。利用這個功能我們可以直接觀察到某一功能實現的整體流程,也方便在閱讀代碼時在不同類切換。

以加載配置文件為例,這里給出整個調用鏈。

上圖中下面的紅框是我們寫的代碼,即就是我們應該開始的地方。下面的紅框就是加載配置文件結束的地方。中間既是整體流程的實現過程。在閱讀配置文件加載的源碼時我們只需要關心這一部分的內容即可。

需要知道的是這里展示出來的僅僅只是跟這個過程密切相關的一些方法。實際上在這個過程中還有需要的方法被執行,只不過執行完畢后方法棧彈出所以不顯示在這里。不過大多數方法都是在為這個流程做準備,所以基本上我們也不用太在意這部分內容

refresh()

前面的關于的構造函數部分沒有啥好說的,在構造函數中調用了一個方法。該方法非常重要,在創建IOC容器的過程中該方法基本上是全程參與。主要功能為用于加載配置或這用于刷新已經加載完成的容器配置。通過該方法可以在運行過程中動態的加入配置文件等:

AbstractApplicationContext#refresh

這里將于當前功能不相關的部分刪除掉了,可以看到進入方法后就會進入一個同步代碼塊。這是為了防止在同一時間有多個線程開始創建IOC容器造成重復實例化。

方法主要用于設置一些日志相關的信息,比如容器啟動時間用于計算啟動容器整體用時,以及設置一些變量用來標識當前容器已經被激活,后續不會再進行創建。

```

該方法首先判斷是否已經實例化好BeanFactory,如果已經實例化完成則將已經實例化好的BeanFactory銷毀。

然后通過new關鍵字創建一個BeanFactory的實現類實例,設置好相關信息。方法用于設置是否運行當beanName重復是修改bean的名稱(allowBeanDefinitionOverriding)和是否運行循環引用(allowCircularReferences)。

```

```

就是讀取配置文件并將其內容解析為一個Document的過程。解析xml一般來說并不需要我們特別的去掌握,稍微有個了解即可,spring這里使用的解析方式為Sax解析,有興趣的可以直接搜索相關文章,這里不進行介紹。下面的才是我們需要關注的地方。

registerBeanDefinitions(Document,Resource)

在進入該方法后首先創建了一個的實例,這和之前的用于讀取xml的reader類一樣,只不過該類是用于從xml文件中讀取。

Environment

在上面的代碼中給Reader設置了Environment,這里談一下關于Environment。

Environment是對spring程序中涉及到環境有關的一個描述集合,主要分為profile和properties。

profile是一組bean定義的集合,通過profile可以指定不同的配置文件用以在不同的環境中,如測試環境,生產環境的配置分開。在部署時只需要配置好當前所處環境值即可按不同分類加載不同的配置。

profile支持xml配置和注解的方式。

也可以通過注解配置:

然后在啟動時根據傳入的環境值加載相應的配置。

properties是一個很寬泛的定義,其來源很多如properties文件,JVM系統變量,系統環境變量,JNDI,servlet上下文參數,Map等。spring會讀取這些配置并在environment接口中提供了方便對其進行操作的方法。

總之就是設計到跟環境有關的直接來找Environment即可。

handler

代碼接著往下走,這一步很明顯就是從解析好的document對象中讀取BeanDefinition的過程,但是在此之前我們先要關注一下方法。

先來看一個XML文件。

上面是xml中根元素定義部分,可能平時并沒有太多人注意。其屬性中的xmlns是XMLNameSpace的縮寫。namespace的作用主要是為了防止在xml定義的節點存在沖突的問題。比如上面聲明了mvc的namespace:。在xml文件中我們就可以使用mvc了:

而實際上在spring中還根據上面定義的namespace來準備了各自的處理類。這里因為解析過程就是將xml定義的每一個節點取出根據配置好的屬性和值來初始化或注冊bean,為了保證代碼可讀性和明確的分工,每一個namespace通過一個專有的handler來處理。

跟蹤方法,最終來到類的構造方法中。

可以看到默認的handler是通過一個本地文件來進行映射的。該文件存在于被依賴jar包下的META-INF文件夾下的spring.handlers文件中。

這里只是展示了beans包下的映射文件,其他如aop包,context包下都有相應的映射文件。通過讀取這些配置文件來映射相應的處理類。在解析xml時會根據使用的namespace前綴使用對應的handler類解析。這種實現機制其實就是所謂的SPI(ServiceProviderInterface),目前很多的應用都在實現過程中使用了spi,如dubbo,mysql的jdbc實現等,有興趣的可以取了解一下。

doRegisterBeanDefinitions(Element)

到這一步中間省略了一個方法,很簡單沒有分析的必要。

delegate

這里的delegate是對BeanDefinitionParse功能的代理,提供了一些支持解析過程的方法。我們可以看到上面有一個重新創建delegate同時又將之前的delegate保存的代碼。注釋上說是為了防止嵌套的beans標簽遞歸操作導致出錯,但是注釋后面又說這并不需要這樣處理,這個操作真的看不懂了,實際上我認為即使遞歸應該也是沒有影響的。還是我理解錯了?

創建好delegate后下面的if語句塊就是用來判斷當前加載的配置文件是否是當前使用的profile指定的配置文件。上面在介紹Environment的時候已經介紹過來,如果這里加載的配置文件和profile指定的不符則直接結束。

publicbooleanisDefaultNamespace(StringnamespaceUri){//BEANS_NAMESPACE_URI="http://www.springframework.org/schema/beans"return(!StringUtils.hasLength(namespaceUri)||BEANS_NAMESPACE_URI.equals(namespaceUri));}

```

接下來的可以算是我們本次目標最重要的一步了,前面所有的流程都是給這一步鋪墊。通過該方法將解析出來的BeanDefinition注冊到容器中,方便實例化。

方法接收兩個參數holder和registry,如果有看過我手寫系列的文章(IOC篇)應該知道,當時為了將bean定義和容器關聯起來以及為了將的功能簡化,所以我們定義了一個接口用于將注冊到容器中和從容器中取,這里的registry功能也是一樣的。(被實現,而實際就是容器)

而且可以看到實際上這里也是通過beanName來區分BeanDefinition是否重復(實際上肯定是我仿的spring的(笑)),只不過為了運行名稱相同的BeanDefinition注冊提供了alias,之前在實現ioc時沒有實現這一步。

在方法的最后一步實際上是注冊了一個listener,在一個被注冊后觸發,只不過上spring中實際觸發方法是一個空方法,如果我們需要在注冊完成后做一些什么工作可以直接繼承后實現方法即可。

到這里基本上關于BeanDefinition的加載就完成了,后面就是重復上面的流程加載多個配置文件。

小結

本節主要介紹了我關于學習spring源碼的一些方法,以及以spring的BeanDefinition的加載為例分析了其整體的流程,希望對大家能有所幫助。還要提的是spring源碼很復雜,如果只是開斷點一路調試下去肯定是不夠的,看的過程中需要多做筆記。由于該文章內容較多以及本人水平問題,文章中可能會存在錯誤,如果有可以指出來方便修改。

注冊bean的方式

注冊Bean的方式有三種:xml方式、注解方式和JavaConfig方式xml方式需要在xml文件中進行配置,而注解方式則需要在類中加上相應的注解,在Spring容器中讀取ApplicationContext中的類,根據注解進行配置而JavaConfig方式是通過編寫Java代碼的方式進行Bean的注入在實際開發中,根據需要選擇不同的方式進行Bean的注冊,如果是維護一個老項目或者Bean較少的情況下,xml方式可以使用而對于新項目或者Bean數量較多的情況下,可以選擇使用注解或者JavaConfig方式進行Bean的注冊

springboot注入初始化方法

在SpringBoot中,可以使用初始化方法來進行依賴注入。通過在需要進行依賴注入的類上使用注解如@Autowired或@Inject,SpringBoot會在應用程序啟動時自動掃描這些標注的類,并根據類的依賴關系進行自動裝配。

初始化方法可以通過在類中定義帶有注解@PostConstruct的方法來實現,該方法會在依賴注入完成后立即執行。

這樣可以在初始化方法中進行一些初始化操作,如數據庫連接、創建對象等,以確保依賴注入完成后執行所需的邏輯。

spring如何發現所有的bean類型

1、在初始化時保存ApplicationContext對象;2、通過Spring提供的utils類獲取ApplicationContext對象;3、繼承自抽象類ApplicationObjectSupport;4、繼承自抽象類WebApplicationObjectSupp

ort;5、實現接口ApplicationContext

Aware;6、通過Spring提供的ContextLoader。

Java程序員如何突破三年的門檻

工作3年了,同樣是程序員,為什么別人每月28K你卻只有16K,如何才能突破自己得到持續成長呢?這是每一個程序員都繞不開的話題。在這里和大家分享我從程序員進階成為java高級工程師/架構師的一些學習方向,Java進階之路離不開一個長期系統的學習規劃,方向方法正確了,結果自然是好的。以下,enjoy~

一、常見模式與工具

1.常用設計模式:Proxy代理模式、Factory工廠模式、Singieton單例模式等

2.Spring5:IOC容器設計原理及高級特性,AOP設計原理、FactoryBean與BeanFactory,Spring事務處理機制等

3.MyBatis:代碼自動生成品,緩存使用場景及選擇策略,MyBatis的事務分析MyBatis的動態代理的真正實現等

二、常用工具

1.Maven:項目管理

2.Jenkins:持續集成

3.Sonar:代碼質量管理

4.Git:版本管理

三、分布式架構

1.架構原理

2.架構策略

3.中間件

4.架構實戰

四、微服務架構

1.微服務框架

2.SpringCloud

3.Docker與虛擬化

4.微服務架構

五、性能優化

1.性能指標體系

2.JVM調優

3.Tomcat調優

4.MySQL調優

六、底層知識

1.內存模型

2.并發模式

3.線程模型

4.鎖細節

以上,只是列舉一個大概的學習方向,工作幾年,走著走著,我們就會發現,身邊總有些程序員成長得特別快,對此,不能一葉障目,只見他人加薪晉級,卻看不見他人工作之余對學習的堅持不懈。人生機會并不多,當下努力,以后才能有更多自由與選擇。以下福利,送給希望進階成為架構師的你,助力進階加薪~

【福利】由BAT背景架構師原創出品的java架構師學習80期專題資料合集,私信關鍵詞【架構】給優知學院,立即免費秒領。

都劃到這兒了,點個贊唄!

都劃到這兒了,點個贊唄!

beanpostprocessor的使用場景

BeanPostProcessor是Spring框架中的一個擴展點,用于在對象實例化、依賴注入和初始化的生命周期過程中介入一些自定義邏輯。可以用于實現一些通用的業務邏輯,比如實現Bean對象屬性的加解密、對象屬性的校驗等。具體來說,它主要有以下兩個使用場景:

1.在Bean實例前后做一些處理,比如對Bean對象的屬性進行加密解密、校驗等操作;

2.在Bean屬性注入完成后做一些處理,比如對Bean對象進行一些AOP操作。

需要注意的是,BeanPostProcessor的使用需要謹慎,因為過多的處理可能會影響Bean的性能和穩定性。因此,在使用時需要仔細考慮其使用場景和實現細節。

關于bean實例化和初始化的區別的內容到此結束,希望對大家有所幫助。

返回列表
上一篇:
下一篇: