淘汰pos機(jī)行情

 新聞資訊2  |   2023-07-12 09:41  |  投稿人:pos機(jī)之家

網(wǎng)上有很多關(guān)于淘汰pos機(jī)行情,2023年再不會(huì) IOC 源碼的知識(shí),也有很多人為大家解答關(guān)于淘汰pos機(jī)行情的問題,今天pos機(jī)之家(www.www690aa.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來看下吧!

本文目錄一覽:

1、淘汰pos機(jī)行情

淘汰pos機(jī)行情

Spring IOC源碼解析一、引言

對(duì)于Java開發(fā)者而言,關(guān)于 Spring ,我們一般當(dāng)做黑盒來進(jìn)行使用,不需要去打開這個(gè)黑盒。

但隨著目前程序員行業(yè)的發(fā)展,我們有必要打開這個(gè)黑盒,去探索其中的奧妙。

本期 Spring 源碼解析系列文章,將帶你領(lǐng)略 Spring 源碼的奧秘

本期源碼文章吸收了之前 Kafka 源碼文章的錯(cuò)誤,將不再一行一行的帶大家分析源碼,我們將一些不重要的部分當(dāng)做黑盒處理,以便我們更快、更有效的閱讀源碼。

廢話不多說,發(fā)車!

本文流程圖可關(guān)注公眾號(hào):愛敲代碼的小黃,回復(fù):IOC 獲取 貼心的小黃為大家準(zhǔn)備的文件格式為 POS文件,方便大家直接導(dǎo)入 ProcessOn 修改使用

二、Spring啟動(dòng)配置

首先,我們要引入 Spring 的依賴,這里是用的 4.3.11.RELEASE 版本的,不同的版本源碼較有差異,但整體業(yè)務(wù)邏輯不變

這里講個(gè)小細(xì)節(jié),如果你在面試,這里一定要提前給面試官說好你閱讀的源碼版本,有三方面好處: 第一:避免不同版本的Spring源碼不一致導(dǎo)致和面試官的分歧問題 第二:讓面試官感覺你小子是真的閱讀過源碼,就算你說的邏輯和面試官有分歧,面試官第一反應(yīng)會(huì)是源碼版本差異導(dǎo)致的 第三:裝逼使用......

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.11.RELEASE</version></dependency>復(fù)制代碼

創(chuàng)建接口 MessageService:

public interface MessageService { String getMessage();}復(fù)制代碼

實(shí)現(xiàn)類 MessageServiceImpl :

public class MessageServiceImpl implements MessageService { public String getMessage() { return "hello world"; }}復(fù)制代碼

配置文件 application.xml

<?xml version="1.0" encoding="UTF-8"?><BEANs xmlns="http://www.springframework.org/schema/Beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="messageService" class="cn.hls.spring.MessageServiceImpl"/></beans>復(fù)制代碼

啟動(dòng)類 SpringStart:

public class SpringStart { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); System.out.println("context 啟動(dòng)成功"); MessageService messageService = context.getbean(MessageService.class); // 輸出: hello world System.out.println(messageService.getMessage()); }}復(fù)制代碼

最終輸出結(jié)果:

context 啟動(dòng)成功hello world復(fù)制代碼

通過上述代碼,我們可以看到,Spring 的 IOC 完全代替了我們之前的 new 的功能,將創(chuàng)建實(shí)例交由 Spring 來管理。

三、IOC 源碼剖析

那 Spring 是如何管理的呢?源碼背后又有什么小技巧呢?今天我們一起來看一下 IOC 源碼的解析

為了閱讀性,我們將以 xml 文件的配置來閱讀源碼

首先,我們從 ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); 這一行入手,看其到底執(zhí)行了什么

我們 debug 點(diǎn)進(jìn)去可以看到共分為了三部分:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent){ super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); }}復(fù)制代碼

簡(jiǎn)單來說,這三部分的作為分別是:

super(parent):調(diào)用父類的構(gòu)造方法,創(chuàng)建 PathMathingResourcePatternResolver 解析配置文件setConfigLocations(configLocations):設(shè)置 configLocations(配置文件路徑) 到當(dāng)前應(yīng)用程序中refresh():解析配置文件、完成bean的注冊(cè)、實(shí)例化、初始化、代理等一系列的工作最終創(chuàng)建出一個(gè) Bean 實(shí)例

我們一起來看一下 refresh 到底做了什么

1、prepareRefresh

**整體簡(jiǎn)介:**做容器刷新前的準(zhǔn)備工作

設(shè)置容器的啟動(dòng)時(shí)間:this.startupDate = System.currentTimeMillis();設(shè)置活躍狀態(tài)為 true:active.set(true)設(shè)置關(guān)閉狀態(tài)為 false:closed.set(false)獲取 Environment 對(duì)象,并加載當(dāng)前系統(tǒng)的屬性值到 Environment 對(duì)象中準(zhǔn)備監(jiān)聽器和事件的集合對(duì)象,默認(rèn)為空的集合:earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();

這個(gè)方法不重要,也不必要去深入了解,知道做了容器刷新的準(zhǔn)備工作即可。

2、obtainFreshBeanFactory

**整體簡(jiǎn)介:**創(chuàng)建容器,并且完成配置文件的加載

重要的來了,這個(gè)方法是比較重要的,一定要記住

首先該方法分為了以下幾部分:

refreshBeanFactory:解析我們的 application.xml 文件并生成 BeanDefinition 注冊(cè)至 DefaultListableBeanFactory 的 beanDefinitionMap 中g(shù)etBeanFactory:獲取工廠bean2.1 refreshBeanFactory

protected final void refreshBeanFactory() throws BeansException { // 創(chuàng)建 BeanFactory,類型為 DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; }}復(fù)制代碼

上述我們必須記住這個(gè)工廠類:DefaultListableBeanFactory,甚至要做到背誦+默寫的程度

其次,最重要的就屬 loadBeanDefinitions(beanFactory) 方法了

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory){ // 創(chuàng)建XmlBeanDefinitionReader,這個(gè)是我們xml文件的解析器 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); // 加載BeanDefinitions loadBeanDefinitions(beanDefinitionReader);}復(fù)制代碼

我們繼續(xù)深入看其做了什么

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { // 拿到xml文件的地址 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); }}復(fù)制代碼

繼續(xù)往下看,一直到 loadBeanDefinitions

public int loadBeanDefinitions(String location, Set<Resource> actualResources){ ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader instanceof ResourcePatternResolver) { try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); // 直接看這行,其余不重要 int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } return loadCount; } } else { Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } return loadCount; }}復(fù)制代碼

XmlBeanDefinitionReader 第 388 行

// 將路徑封裝成一個(gè)DOC格式Document doc = doLoadDocument(inputSource, resource);// 繼續(xù)注冊(cè)return registerBeanDefinitions(doc, resource);復(fù)制代碼

XmlBeanDefinitionReader 第 505 行

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getregistry().getBeanDefinitionCount(); // 其余不重要,直接看這行 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore;}public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; // 獲取根節(jié)點(diǎn) Element root = doc.getDocumentElement(); // 從根節(jié)點(diǎn)開始解析遍歷 doRegisterBeanDefinitions(root);}protected void doRegisterBeanDefinitions(Element root) {BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(getReaderContext(), root, parent);if (this.delegate.isDefaultNamespace(root)) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);}}preProcessXml(root); // 直接看這里,其余不重要parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent;}復(fù)制代碼

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // 直接看這里 parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); }}// 根據(jù)不同的配置走不同的分支,配置:IMPORT、alias、bean、beansprivate void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}}復(fù)制代碼

我們這里只看 bean 的配置,其余的讀者有興趣可以自己去 debug 下

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 解析各種xml標(biāo)簽去生成對(duì)應(yīng)的BeanDefinition,讀者有興趣可以自己看一下 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 重點(diǎn):正式開始注冊(cè) BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); }}public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {// 重點(diǎn),開始注冊(cè)String beanName = definitionHolder.getBeanName();registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 注冊(cè)別名String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}}}public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {// 看一下原來的beanDefinitionMap是不是已經(jīng)有該 beanName 了 // 如果已經(jīng)存在,我們要排拋出異常(Spring不允許覆蓋)BeanDefinition oldBeanDefinition = this.beanDefinitionMapbeanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException() } }if (oldBeanDefinition != null) {this.beanDefinitionMap.put(beanName, beanDefinition);}else { // 重點(diǎn)在這:將我們的beanName與beanDefinition放至beanDefinitionMap中this.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}}復(fù)制代碼

到這里,基本就結(jié)束了,我們來回顧一下 refreshBeanFactory 的業(yè)務(wù):

通過我們傳遞的xml 文件的路徑,利用 documentLoader 將其封裝成 Document 格式創(chuàng)建 BeanDefinitionDocumentReader 來正式解析 xml 文件并找到文件的 root根據(jù) root 掃描遍歷,對(duì)不同配置的標(biāo)簽(import、alias、bean、beans)走不同的邏輯判斷將當(dāng)前的標(biāo)簽各屬性進(jìn)行組裝成 beanDefinition,調(diào)用 DefaultListableBeanFactory 進(jìn)行注冊(cè)根據(jù) BeanName 查詢?cè)?beanDefinition 是否被注冊(cè)過,如果被注冊(cè)過,則直接拋出異常(Spring不允許覆蓋)如果沒有注冊(cè)過,則將 BeanName 與 beanDefinition 注冊(cè)至 DefaultListableBeanFactory 的 beanDefinitionMap 中最后,如果該 beanDefinition 含有別名,也要將別名進(jìn)行注冊(cè),至于為什么注冊(cè)別名,可見:附錄1

這里可能有人會(huì)說,小黃小黃,按你之前解析 kafka 的套路,肯定會(huì)分析 beanDefinition 的形成的,現(xiàn)在怎么偷懶不分析了,是不是看不懂~

答:之前分享的 kafka 系列的文章,大家都知道分享的很細(xì),但是我們細(xì)細(xì)品味一下,我們讀源碼到底為了什么,以及如何去讀、如何有效的讀、如何快速的讀,我相信每一個(gè)人心中都有一套讀源碼的方式。至于哪一種閱讀方式更為合理,后面博主準(zhǔn)備單獨(dú)出一篇文章來講解,或者你可以私信我,告知我你的讀源碼的方式,一起加油、一起學(xué)習(xí)。

3、prepareBeanFactory

整體簡(jiǎn)介: beanFactory 的準(zhǔn)備工作,對(duì)各種屬性進(jìn)行填充

這個(gè)方法不重要,也不必要去深入了解,知道做了 beanFactory 的填充即可

不過,這里記住,beanFactory 的類一定要記清楚,是 DefaultListableBeanFactory ,不多說直接 背誦+默寫

4、postProcessBeanFactory

整體簡(jiǎn)介: 默認(rèn)沒有實(shí)現(xiàn),留給子類進(jìn)行實(shí)現(xiàn)操作

5、invokeBeanFactoryPostProcessors

整體簡(jiǎn)介: 可以自由擴(kuò)展,通過實(shí)現(xiàn)BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 接口,對(duì) beanFactory 里面的 BeanDefinition 進(jìn)行修改

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 找到當(dāng)前 beanDefinitionMap 中`BeanFactoryPostProcessor` 和 `BeanDefinitionRegistryPostProcessor`接口的實(shí)現(xiàn) // 若這些實(shí)現(xiàn)有對(duì)應(yīng)的order(順序),則排序之后依次調(diào)用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}復(fù)制代碼

溫馨小提示:這里有的小伙伴可能對(duì) BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 接口不熟悉,我們將此處的講解放至:附錄2

6、registerBeanPostProcessors

整體簡(jiǎn)介: 完成 spring 自帶或者用戶自定義的 BeanPostProcessor 的解析

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 實(shí)例化并且注冊(cè)所有的beanPostProcessor PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}復(fù)制代碼

這里的操作實(shí)際上和我們上面 invokeBeanFactoryPostProcessors 里面很像,都是對(duì)實(shí)現(xiàn)一些特定接口的類做加載,但需要注意的是:對(duì)于實(shí)現(xiàn) BeanPostProcessor 接口的來說,我們不會(huì)在此立即調(diào)用,會(huì)在 Bean 初始化方法前后調(diào)用。

對(duì)了,提前劇透一下,我們響當(dāng)當(dāng)?shù)?AOP 也是在這里實(shí)現(xiàn)的,后續(xù)我們也會(huì)講的。

溫馨小提示:這里有的小伙伴可能對(duì) BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 接口不熟悉,我們將此處的講解放至:附錄3

7、initMessageSource

整體簡(jiǎn)介: Spring 中國(guó)際化的功能

8、initApplicationEventMulticaster

整體簡(jiǎn)介: 初始化事件廣播器

9、onRefresh

整體簡(jiǎn)介: 在 spring 中默認(rèn)沒有任何實(shí)現(xiàn),模板方法,但是在 springboot 中啟動(dòng)了 web 容器

10、registerListeners

整體簡(jiǎn)介: 注冊(cè)監(jiān)聽器,為了方便接受廣播的事件

11、finishBeanFactoryInitialization

整體簡(jiǎn)介:完成所有非懶加載的單例對(duì)象的實(shí)例化操作,從此方法開始進(jìn)行對(duì)象的創(chuàng)建,包含了實(shí)例化,初始化,循環(huán)依賴,AOP等核心邏輯的處理過程,此步驟是最最核心且關(guān)鍵的點(diǎn),要對(duì)其中的細(xì)節(jié)最夠清楚

由于篇幅原因,博主會(huì)盡量挑選一些重要的地方進(jìn)行分析。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 實(shí)例化剩下的單例對(duì)象 beanFactory.preInstantiateSingletons();}public void preInstantiateSingletons(){ // 拿到我們之前存儲(chǔ)的所有beanDefinition的名字List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// 觸發(fā)單例bean的初始化,遍歷集合的對(duì)象for (String beanName : beanNames) { // 如果beanName對(duì)應(yīng)的bean不是FactoryBean,只是普通的bean,通過beanName獲取bean實(shí)例 getBean(beanName); }}public Object getBean(String name) throws BeansException { // 此方法是實(shí)際獲取bean的方法,也是觸發(fā)依賴注入的方法 return doGetBean(name, null, null, false);}protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly){ // 這里需要一步轉(zhuǎn)換,這里的原因我們附錄1提到過,這里不再過多討論 String beanName = transformedBeanName(name); // 提前檢查單例緩存中是否有手動(dòng)注冊(cè)的單例對(duì)象,劇透一下(和循環(huán)依賴有關(guān)聯(lián)) Object sharedInstance = getSingleton(beanName); // 當(dāng)對(duì)象都是單例的時(shí)候會(huì)嘗試解決循環(huán)依賴的問題,但是原型模式下如果存在循環(huán)依賴的情況,那么直接拋出異常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } if (mbd.isSingleton()) { // 返回以beanName的(原始)單例對(duì)象,如果尚未注冊(cè),則使用singletonFactory創(chuàng)建并注冊(cè)一個(gè)對(duì)象: sharedInstance = getSingleton(beanName, () -> { try { // 為給定的合并后BeanDefinition(和參數(shù))創(chuàng)建一個(gè)bean實(shí)例 // 這也是我們的核心方法 return createBean(beanName, mbd, args); } });} protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){ // 實(shí)際創(chuàng)建bean的調(diào)用 Object beanInstance = doCreateBean(beanName, mbdToUse, args);} protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){ // 根據(jù)執(zhí)行bean使用對(duì)應(yīng)的策略創(chuàng)建新的實(shí)例,如,工廠方法,構(gòu)造函數(shù)主動(dòng)注入、簡(jiǎn)單初始化 BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); // 對(duì)bean的屬性進(jìn)行填充,將各個(gè)屬性值注入,其中,可能存在依賴于其他bean的屬性,則會(huì)遞歸初始化依賴的bean populateBean(beanName, mbd, instanceWrapper); // 執(zhí)行初始化邏輯 exposedObject = initializeBean(beanName, exposedObject, mbd);}復(fù)制代碼

到這里我們先停一停,我們總結(jié)一下創(chuàng)建實(shí)例的一些步驟:

拿到我們之前注冊(cè)的 beanDefinitionNames,遍歷整個(gè) beanDefinitionNames,每一個(gè) BeanName 生成一個(gè)對(duì)象我們需要進(jìn)行名稱轉(zhuǎn)化,防止傳入的是一個(gè)別名或其他的名稱,利用轉(zhuǎn)換后的別名去調(diào)用查詢我們的單例緩存中是否已經(jīng)存在該實(shí)例,如果存在直接返回即可如果不存在,則需要去根據(jù)該 beanDefinition 去生成對(duì)應(yīng)的實(shí)例對(duì)于生成實(shí)例共有三個(gè)步驟:創(chuàng)建實(shí)例屬性填充初始化邏輯 實(shí)現(xiàn) BeanPostProcessor 的前置方法 對(duì)象的初始化方法 實(shí)現(xiàn) BeanPostProcessor 的后置方法

我們對(duì)于每個(gè)步驟都進(jìn)行分析:

11.1 創(chuàng)建實(shí)例

對(duì)于實(shí)例創(chuàng)建,Spring 中創(chuàng)建 bean 的方式大致可分為三種:

類名稱 + 自定義 beanName工廠類名稱+ 自定義工廠靜態(tài)方法 + 自定義 beanName提前注冊(cè)工廠bean,使用工廠bean + 工廠方法+自定義 beanName

可能大家有點(diǎn)懵,怎么這么多創(chuàng)建的方法,這里其實(shí)我們不需要太過于關(guān)注,只需要關(guān)注 類名稱 + 自定義 beanName 這種方法即可,其余兩種基本很少用到

對(duì)于 類名稱 + 自定義 beanName 我們一般有兩種構(gòu)造方法:

無參構(gòu)造(常用)有參構(gòu)造(不常用)

為了便于理解,我們這里只介紹無參構(gòu)造

BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { // 根據(jù)當(dāng)前的beanName拿到其 Class Class<?> beanClass = resolveBeanClass(mbd, beanName); // 前面的有參都不存在,則進(jìn)行無參構(gòu)造 return instantiateBean(beanName, mbd);}protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) { // 獲取實(shí)例化策略并且進(jìn)行實(shí)例化操作 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);}public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // 鎖一下對(duì)象,線程安全 synchronized (bd.constructorArgumentLock) { // 得到當(dāng)前bean的Class Class<?> clazz = bd.getBeanClass(); // 通過class得到其默認(rèn)的構(gòu)造方法 constructorToUse = clazz.getDeclaredConstructor(); // return BeanUtils.instantiateClass(constructorToUse); }}public static <T> T instantiateClass(Constructor<T> ctor, Object... args) { // 構(gòu)造方法+入?yún)? // 如果當(dāng)前是無參構(gòu)造方法的話,則argsWithDefaultValues為空 return ctor.newInstance(argsWithDefaultValues);}復(fù)制代碼

總結(jié)一下通過無參構(gòu)造創(chuàng)建實(shí)例的步驟:

加鎖,保證線程安全得到當(dāng)前 bean 的 Class,通過其 Class 得到默認(rèn)的無參構(gòu)造方法通過反射直接創(chuàng)建即可

其實(shí)有參的構(gòu)造方法也類似,只不過相較于無參構(gòu)造,反射傳入的 argsWithDefaultValues 的參數(shù),這里的參數(shù)可以為 Bean 也可以為數(shù)值,所以這里也會(huì)出現(xiàn)循環(huán)依賴的問題。

11.2 屬性填充

屬性填充相對(duì)簡(jiǎn)單,流程我們大致過一下,屬性注入類似:

<bean id="messageService" class="com.mashibing.hls.MessageServiceImpl"> <property name="name" value="hls"/></bean>復(fù)制代碼

其中的 property 標(biāo)簽就是我們的屬性值。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { // 得到當(dāng)前 BeanDefinition 的屬性值 PropertyValues pvs = mbd.getPropertyValues(); if (pvs != null) { // 注入屬性 applyPropertyValues(beanName, mbd, bw, pvs); }}protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs){ // 獲取pvs的PropertyValue對(duì)象數(shù)組,并將其轉(zhuǎn)換成列表 List<PropertyValue> original = Arrays.asList(pvs.getPropertyValues()); for (PropertyValue pv : original) { // 獲取屬性的名字 String propertyName = pv.getName(); // 獲取未經(jīng)類型轉(zhuǎn)換的值 Object originalValue = pv.getValue(); // 這里需要進(jìn)行一系列的轉(zhuǎn)換 // 因?yàn)槲覀兊膶傩宰⑷胗锌赡茏⑷氲氖且粋€(gè)BeanReference,需要重新去 BeanFactory 中獲取實(shí)例 // 轉(zhuǎn)換后的放至 deepCopy // 按原樣使用deepCopy構(gòu)造一個(gè)新的MutablePropertyValues對(duì)象然后設(shè)置到bw中以對(duì)bw的屬性值更新 bw.setPropertyValues(new MutablePropertyValues(deepCopy)); }}public void setPropertyValues(PropertyValues pvs){ setPropertyValues(pvs, false, false);}public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid){ // 后續(xù)主要通過反射對(duì)值進(jìn)行設(shè)置,感興趣的可以自己去看下源碼實(shí)現(xiàn) setPropertyValue(pv);}復(fù)制代碼11.3 初始化邏輯

我們這里先實(shí)現(xiàn)一個(gè) BeanPostProcessor 接口,便于我們的觀察:

public class MyTest implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("我前置增強(qiáng)"); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("我后置增強(qiáng)"); return bean; }}復(fù)制代碼

直接看我們的源碼:

// 執(zhí)行初始化邏輯exposedObject = initializeBean(beanName, exposedObject, mbd);protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { // 將BeanPostProcessors應(yīng)用到給定的現(xiàn)有Bean實(shí)例,調(diào)用它們的postProcessBeforeInitialization初始化方法。 // 返回的Bean實(shí)例可能是原始Bean包裝器 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);//調(diào)用初始化方法,先調(diào)用bean的InitializingBean接口方法,后調(diào)用bean的自定義初始化方法invokeInitMethods(beanName, wrappedBean, mbd);// 將BeanPostProcessors應(yīng)用到給定的現(xiàn)有Bean實(shí)例,調(diào)用它們的postProcessAfterInitialization方法。// 返回的Bean實(shí)例可能是原始Bean包裝器wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//返回包裝后的Beanreturn wrappedBean;}// 執(zhí)行所有的BeanPostProcessors接口下的類// 如果我們自己實(shí)現(xiàn)的類對(duì) Bean 進(jìn)行了包裝,比如AOP,則使用我們實(shí)現(xiàn)類里面返回的public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName){ Object result = existingBean;//遍歷 該工廠創(chuàng)建的bean的BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {// 默認(rèn)實(shí)現(xiàn)按原樣返回給定的 BeanObject current = processor.postProcessBeforeInitialization(result, beanName);// 如果 current為nullif (current == null) {//直接返回result,中斷其后續(xù)的BeanPostProcessor處理return result;}//讓result引用processor的返回結(jié)果,使其經(jīng)過所有BeanPostProcess對(duì)象的后置處理的層層包裝result = current;}//返回經(jīng)過所有BeanPostProcess對(duì)象的后置處理的層層包裝后的resultreturn result;}protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd){ // 如果mbd不為null&&bean不是NullBean類if (mbd != null && bean.getClass() != NullBean.class) {// 獲取mbd指定的初始化方法名String initMethodName = mbd.getInitMethodName();// 在bean上調(diào)用指定的自定義init方法invokeCustomInitMethod(beanName, bean, mbd); // 具體調(diào)用,反射執(zhí)行 // Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);// methodToInvoke.invoke(bean);}}// 執(zhí)行所有的BeanPostProcessors接口下的類// 如果我們自己實(shí)現(xiàn)的類對(duì) Bean 進(jìn)行了包裝,比如AOP,則使用我們實(shí)現(xiàn)類里面返回的public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName){//初始化結(jié)果對(duì)象為result,默認(rèn)引用existingBeanObject result = existingBean;//遍歷該工廠創(chuàng)建的bean的BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {//回調(diào)BeanPostProcessor#postProcessAfterInitialization來對(duì)現(xiàn)有的bean實(shí)例進(jìn)行包裝Object current = processor.postProcessAfterInitialization(result, beanName);// 如果current為nullif (current == null) {//直接返回result,中斷其后續(xù)的BeanPostProcessor處理return result;}//讓result引用processor的返回結(jié)果,使其經(jīng)過所有BeanPostProcess對(duì)象的后置處理的層層包裝result = current;}//返回經(jīng)過所有BeanPostProcess對(duì)象的后置處理的層層包裝后的resultreturn result;}

其實(shí)初始化的邏輯也很簡(jiǎn)單,就是調(diào)用我們的 BeanPostProcess 實(shí)現(xiàn)擴(kuò)展點(diǎn)的應(yīng)用

然后初始化 init 方法即可

12、finishRefresh

整體簡(jiǎn)介: 完成整個(gè)容器的啟動(dòng),所有的對(duì)象都準(zhǔn)備完成,可以進(jìn)行后續(xù)業(yè)務(wù)流程的操作,清除上下文緩存,初始化生命周期處理器,發(fā)送刷新完成事件

13、銷毀

前面我們已經(jīng)創(chuàng)建成功了對(duì)象,當(dāng)我們使用完成之后,肯定要進(jìn)行銷毀,那么 Spring 是如何做的銷毀對(duì)象的管理呢

執(zhí)行 context.close(); 方法:

public void close() { synchronized (this.startupShutdownMonitor) { doClose(); }}protected void doClose() { // 清空 DefaultListableBeanFactory 里面的緩存 destroyBeans(); // 直接將beanFactory置為null closeBeanFactory();}protected void destroyBeans() { // 清空在包含的Bean名稱之間映射:bean名稱-Bean包含的Bean名稱集 this.containedBeanMap.clear(); // 清空在相關(guān)的Bean名稱之間映射:bean名稱-一組相關(guān)的Bean名稱 this.dependentBeanMap.clear(); // 清空在相關(guān)的Bean名稱之j鍵映射:bean名稱bean依賴項(xiàng)的Bean名稱集 this.dependenciesForBeanMap.clear(); // 清除此注冊(cè)表中所有緩存的單例實(shí)例 clearSingletonCache();}protected void clearSingletonCache() { // 加鎖,使用單例對(duì)象的高速緩存:beam名稱-bean實(shí)例作為鎖 synchronized (this.singletonObjects) { // 清空單例對(duì)象的高速緩存:beam名稱-bean實(shí)例 this.singletonObjects.clear(); // 清空單例工廠的緩存:bean名稱-ObjectFactory this.singletonFactories.clear(); // 清空早期單例對(duì)象的高速緩存:bean名稱-bean實(shí)例 this.earlySingletonObjects.clear(); // 清空已注冊(cè)的單例集,按照注冊(cè)順序包含bean名稱 this.registeredSingletons.clear(); // 設(shè)置當(dāng)前是否在destroySingletons中的標(biāo)志為false this.singletonsCurrentlyInDestruction = false; }}private void clearByTypeCache() { this.allBeanNamesByType.clear(); this.singletonBeanNamesByType.clear();}// 直接將beanFactory置空protected final void closeBeanFactory() { DefaultListableBeanFactory beanFactory = this.beanFactory; if (beanFactory != null) { beanFactory.setSerializationId(null); this.beanFactory = null; }}

這基本就是銷毀的整個(gè)流程。

這里還有一個(gè)小知識(shí)點(diǎn),就是我們可以自定義我們的銷毀方法,比如如下:

<bean id="messageService" class="cn.hls.spring.MessageServiceImpl" init-method="init" destroy-method="destroy"/> public class MessageServiceImpl implements MessageService { public String getMessage() { return "hello world"; } public void init(){ System.out.println("我是類的初始化"); } public void destroy(){ System.out.println("我是類的銷毀"); }}復(fù)制代碼

在執(zhí)行 context.close(); 方法時(shí),會(huì)調(diào)用該 Bean 的銷毀方法,至于怎么調(diào)用的。

這里交給讀者了(真不是我懶

五、流程圖六、總結(jié)

記得校招時(shí)候,當(dāng)時(shí)對(duì) Spring 懵懂無知,轉(zhuǎn)眼間也被迫看了源碼

有些小伙伴可能疑惑:哎,博主,你這不對(duì)呀,你這循環(huán)依賴也沒講、三級(jí)緩存也沒講,你是不是漏的有點(diǎn)多。

因?yàn)樵蹅冞@篇文章主要針對(duì)的是 Spring IOC 的源碼,對(duì)于三級(jí)緩存、循環(huán)依賴來說,主要解決 AOP 代理對(duì)象的問題,這個(gè)我們后面單獨(dú)出一篇來描述,不要著急,小黃不會(huì)不講的。

當(dāng)然,本篇只介紹了 XML 配置,如果你對(duì)注解的配置感興趣的話,也可以去看一下 AnnotationConfigApplicationContext 的流程,區(qū)別不大,一個(gè)是解析的 xml,一個(gè)是解析的注解

但通過這篇文章,我相信,99% 的人應(yīng)該都可以理解了 Spring IOC 的來龍去脈

那么如何證明你真的理解了 Spring IOC 呢,我這里出個(gè)經(jīng)典的題目,大家可以想一下:Bean 的生命周期

七、附錄1、注冊(cè)別名的原因

當(dāng)我們使用 GetBean(beanName) 時(shí),Spring會(huì)默認(rèn)其是別名,并進(jìn)行循環(huán)獲取

protected <T> T doGetBean(String name){ final String beanName = transformedBeanName(name);}protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name));}public String canonicalName(String name) { String canonicalName = name; String resolvedName; do { resolvedName = (String)this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while(resolvedName != null); return canonicalName;}2、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor

這兩個(gè)類的作用主要對(duì)我們 BeanFactory 的 BeanDefinitions 進(jìn)行修改,舉個(gè)例子:

public class MyTest implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 拿到我們 id = messageService 的 PropertyValue MutablePropertyValues messageService = beanFactory.getBeanDefinition("messageService").getPropertyValues(); List<PropertyValue> propertyValueList = messageService.getPropertyValueList(); // 遍歷輸出,當(dāng)然也可以進(jìn)行修改 for (PropertyValue propertyValue : propertyValueList) { System.out.println("BeanFactoryPostProcessor : name = " + propertyValue.getName() + " value = " + propertyValue.getValue()); } }}

我們看一下啟動(dòng)的效果:

BeanFactoryPostProcessor : name = name value = TypedStringValue: value [hls], target type [null]3、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor

這兩個(gè)類主要是擴(kuò)展進(jìn)行使用,比如我們的 AOP 或者其他的擴(kuò)展點(diǎn),舉個(gè)例子:

public class MyTest implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("我會(huì)在類初始化前調(diào)用"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("我會(huì)在類初始化后調(diào)用"); return bean; }}

我們看一下啟動(dòng)的效果:

我會(huì)在類初始化前調(diào)用我是類的初始化我會(huì)在類初始化后調(diào)用

以上就是關(guān)于淘汰pos機(jī)行情,2023年再不會(huì) IOC 源碼的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于淘汰pos機(jī)行情的知識(shí),希望能夠幫助到大家!

轉(zhuǎn)發(fā)請(qǐng)帶上網(wǎng)址:http://www.www690aa.com/newsone/83386.html

你可能會(huì)喜歡:

版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 babsan@163.com 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。