您現在的位置是:首頁 > 農業

我想挑戰下我的軟肋,動手實現Spring應用上下文!

由 馬小乎 發表于 農業2022-06-02
簡介定義 BeanFactoryPostProcessorcn.bugstack.springframework.beans.factory.config.BeanFactoryPostProcessorpublicinterfaceBeanF

嘎哈怎麼拼

你這程式碼,可不能寫死了呀!

依照專案落地經驗來看,我們在承接緊急的產品需求時候,通常會選擇在原有同類項目中進行擴充套件,如果沒有相關型別專案的儲備,也可能會選擇臨時搭建出一個工程來實現產品的需求。但這個時候就會遇到非常現實的問題,選擇完整的設計和開發就可能滿足不了上線時間,臨時拼湊式的完成需求又可能不具備上線後響應產品的臨時調整。

上線後的調整有哪些呢?專案剛一上線,運營了還不到半天,老闆發現自己的配置的活動好像金額配置的太小了,使用者都不來,割不到韭菜呀。

趕緊半夜聯絡產品,來來來,你給我這改改,那修修,把人均優惠1萬元放大大的,把可能兩字縮小放在後面。再把優惠的獎金池配置從10元調整11元,快快快,趕緊修改,你修改了咱們能賺1個億!!!

好傢伙,專案是臨時開發堆出來的,沒有後臺系統、沒有配置中心、沒有模組拆分,老闆一句句改改改,產品來傳達催促,最後背鍋的可就是研發了。

你這不能寫死,這優惠配置得抽出來,這文案也後臺下發吧,這介面入參也寫死了,再寫一個新介面吧!

一頓操作猛如虎,研發搬磚修介面,運營折騰好幾宿,最後PV150!

無論業務、產品、運營如何,但就研發自身來講,儘可能的要不避免臨時堆出一個服務來,尤其是在團隊建設初期或者運營思路經常調整的情況下,更要注重設計細節和實現方案。哪怕去報風險延期,也不要讓自己背上一個明知是爛坑還要接的活。

而本章節說到不把程式碼寫死,就是因為我們需要繼續在手寫 Spring 框架中繼續擴充套件新的功能,如一個Bean的定義和例項化的過程前後,是否可以滿足我們進行自定義擴充套件,對Bean物件執行一些修改、增強、記錄等操作呢?

這個過程基本就是你在使用 Spring 容器框架時候做的一些中介軟體擴充套件開發。

二、目標

如果你在自己的實際工作中開發過基於 Spring 的技術元件,或者學習過關於 SpringBoot 中介軟體設計和開發 等內容。那麼你一定會繼承或者實現了 Spring 對外暴露的類或介面,在介面的實現中獲取了 BeanFactory 以及 Bean 物件的獲取等內容,並對這些內容做一些操作,例如:修改 Bean 的資訊,新增日誌列印、處理資料庫路由對資料來源的切換、給 RPC 服務連線註冊中心等。

在對容器中 Bean 的例項化過程新增擴充套件機制的同時,還需要把目前關於 Spring。xml 初始化和載入策略進行最佳化,因為我們不太可能讓面向 Spring 本身開發的

DefaultListableBeanFactory

服務,直接給予使用者使用。修改點如下:

我想挑戰下我的軟肋,動手實現Spring應用上下文!

DefaultListableBeanFactory、XmlBeanDefinitionReader,是我們在目前 Spring 框架中對於服務功能測試的使用方式,它能很好的體現出 Spring 是如何對 xml 載入以及註冊Bean物件的操作過程,但這種方式是面向 Spring 本身的,還不具備一定的擴充套件性。

就像我們現在需要提供出一個可以在 Bean 初始化過程中,完成對 Bean 物件的擴充套件時,就很難做到自動化處理。所以我們要把 Bean 物件擴充套件機制功能和對 Spring 框架上下文的包裝融合起來,對外提供完整的服務。

三、設計

為了能滿足於在 Bean 物件從註冊到例項化的過程中執行使用者的自定義操作,就需要在 Bean 的定義和初始化過程中插入介面類,這個介面再有外部去實現自己需要的服務。那麼在結合對 Spring 框架上下文的處理能力,就可以滿足我們的目標需求了。整體設計結構如下圖:

我想挑戰下我的軟肋,動手實現Spring應用上下文!

滿足於對 Bean 物件擴充套件的兩個介面,其實也是 Spring 框架中非常具有重量級的兩個介面:

BeanFactoryPostProcess和BeanPostProcessor

,也幾乎是大家在使用 Spring 框架額外新增開發自己組建需求的兩個必備介面。

BeanFactoryPostProcessor,是由 Spring 框架組建提供的容器擴充套件機制,允許在 Bean 物件註冊後但未例項化之前,對 Bean 的定義資訊

BeanDefinition

執行修改操作。

BeanPostProcessor,也是 Spring 提供的擴充套件機制,不過 BeanPostProcessor 是在 Bean 物件例項化之後修改 Bean 物件,也可以替換 Bean 物件。這部分與後面要實現的 AOP 有著密切的關係。

同時如果只是新增這兩個介面,不做任何包裝,那麼對於使用者來說還是非常麻煩的。我們希望於開發 Spring 的上下文操作類,把相應的 XML 載入 、註冊、例項化以及新增的修改和擴充套件都融合進去,讓 Spring 可以自動掃描到我們的新增服務,便於使用者使用。

四、實現

1。 工程結構

small-spring-step-06└── src ├── main │ └── java │ └── cn。bugstack。springframework │ ├── beans │ │ ├── factory │ │ │ ├── factory │ │ │ │ ├── AutowireCapableBeanFactory。java │ │ │ │ ├── BeanDefinition。java │ │ │ │ ├── BeanFactoryPostProcessor。java │ │ │ │ ├── BeanPostProcessor。java │ │ │ │ ├── BeanReference。java │ │ │ │ ├── ConfigurableBeanFactory。java │ │ │ │ └── SingletonBeanRegistry。java │ │ │ ├── support │ │ │ │ ├── AbstractAutowireCapableBeanFactory。java │ │ │ │ ├── AbstractBeanDefinitionReader。java │ │ │ │ ├── AbstractBeanFactory。java │ │ │ │ ├── BeanDefinitionReader。java │ │ │ │ ├── BeanDefinitionRegistry。java │ │ │ │ ├── CglibSubclassingInstantiationStrategy。java │ │ │ │ ├── DefaultListableBeanFactory。java │ │ │ │ ├── DefaultSingletonBeanRegistry。java │ │ │ │ ├── InstantiationStrategy。java │ │ │ │ └── SimpleInstantiationStrategy。java │ │ │ ├── support │ │ │ │ └── XmlBeanDefinitionReader。java │ │ │ ├── BeanFactory。java │ │ │ ├── ConfigurableListableBeanFactory。java │ │ │ ├── HierarchicalBeanFactory。java │ │ │ └── ListableBeanFactory。java │ │ ├── BeansException。java │ │ ├── PropertyValue。java │ │ └── PropertyValues。java │ ├── context │ │ ├── support │ │ │ ├── AbstractApplicationContext。java │ │ │ ├── AbstractRefreshableApplicationContext。java │ │ │ ├── AbstractXmlApplicationContext。java │ │ │ └── ClassPathXmlApplicationContext。java │ │ ├── ApplicationContext。java │ │ └── ConfigurableApplicationContext。java │ ├── core。io │ │ ├── ClassPathResource。java │ │ ├── DefaultResourceLoader。java │ │ ├── FileSystemResource。java │ │ ├── Resource。java │ │ ├── ResourceLoader。java │ │ └── UrlResource。java │ └── utils │ └── ClassUtils。java └── test └── java └── cn。bugstack。springframework。test ├── bean │ ├── UserDao。java │ └── UserService。java ├── common │ ├── MyBeanFactoryPostProcessor。java │ └── MyBeanPostProcessor。java └── ApiTest。java

工程原始碼

Spring 應用上下文和對Bean物件擴充套件機制的類關係,如圖 7-3

我想挑戰下我的軟肋,動手實現Spring應用上下文!

在整個類圖中主要體現出來的是關於 Spring 應用上下文以及對 Bean 物件擴充套件機制的實現。

以繼承了 ListableBeanFactory 介面的 ApplicationContext 介面開始,擴展出一系列應用上下文的抽象實現類,並最終完成

ClassPathXmlApplicationContext

類的實現。而這個類就是最後交給使用者使用的類。

同時在實現應用上下文的過程中,透過定義介面:

BeanFactoryPostProcessor

兩個介面,把關於對 Bean 的擴充套件機制串聯進去了。

2。 定義 BeanFactoryPostProcessor

cn.bugstack.springframework.beans.factory.config.BeanFactoryPostProcessor

publicinterfaceBeanFactoryPostProcessor{ /** * 在所有的 BeanDefinition 載入完成後,例項化 Bean 物件之前,提供修改 BeanDefinition 屬性的機制 * * @param beanFactory * @throws BeansException */voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException;}

在 Spring 原始碼中有這樣一段描述

Allows for custom modification of an application context‘s bean definitions,adapting the bean property values of the context’s underlying bean factory。

其實也就是說這個介面是滿足於在所有的 BeanDefinition 載入完成後,例項化 Bean 物件之前,提供修改 BeanDefinition 屬性的機制。

3。 定義 BeanPostProcessor

cn.bugstack.springframework.beans.factory.config.BeanPostProcessor

publicinterfaceBeanPostProcessor{ /** * 在 Bean 物件執行初始化方法之前,執行此方法 * * @param bean * @param beanName * @return * @throws BeansException */Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException; /** * 在 Bean 物件執行初始化方法之後,執行此方法 * * @param bean * @param beanName * @return * @throws BeansException */Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException;}

Factory hook that allows for custom modification of new bean instances,e。g。 checking for marker interfaces or wrapping them with proxies。

也就是提供了修改新例項化 Bean 物件的擴充套件點。

另外此介面提供了兩個方法:

postProcessBeforeInitialization

用於在 Bean 物件執行初始化方法之前,執行此方法、

postProcessAfterInitialization

用於在 Bean 物件執行初始化方法之後,執行此方法。

4。 定義上下文介面

cn.bugstack.springframework.context.ApplicationContext

publicinterfaceApplicationContextextendsListableBeanFactory{}

context 是本次實現應用上下文功能新增的服務包

ApplicationContext,繼承於 ListableBeanFactory,也就繼承了關於 BeanFactory 方法,比如一些 getBean 的方法。另外 ApplicationContext 本身是 Central 介面,但目前還不需要新增一些獲取ID和父類上下文,所以暫時沒有介面方法的定義。

cn.bugstack.springframework.context.ConfigurableApplicationContext

publicinterfaceConfigurableApplicationContextextendsApplicationContext{ /** * 重新整理容器 * * @throws BeansException */voidrefresh()throws BeansException;}

ConfigurableApplicationContext 繼承自 ApplicationContext,並提供了 refresh 這個核心方法。

如果你有看過一些 Spring 原始碼,那麼一定會看到這個方法。

接下來也是需要在上下文的實現中完成重新整理容器的操作過程。

5。 應用上下文抽象類實現

cn.bugstack.springframework.context.support.AbstractApplicationContext

publicabstractclassAbstractApplicationContextextendsDefaultResourceLoaderimplementsConfigurableApplicationContext{ @Overridepublicvoidrefresh()throws BeansException { // 1。 建立 BeanFactory,並載入 BeanDefinition refreshBeanFactory(); // 2。 獲取 BeanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 3。 在 Bean 例項化之前,執行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context。) invokeBeanFactoryPostProcessors(beanFactory); // 4。 BeanPostProcessor 需要提前於其他 Bean 物件例項化之前執行註冊操作 registerBeanPostProcessors(beanFactory); // 5。 提前例項化單例Bean物件 beanFactory。preInstantiateSingletons(); } protectedabstractvoidrefreshBeanFactory()throws BeansException; protectedabstract ConfigurableListableBeanFactory getBeanFactory(); privatevoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory){ Map beanFactoryPostProcessorMap = beanFactory。getBeansOfType(BeanFactoryPostProcessor。class); for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap。values()) { beanFactoryPostProcessor。postProcessBeanFactory(beanFactory); } } privatevoidregisterBeanPostProcessors(ConfigurableListableBeanFactory beanFactory){ Map beanPostProcessorMap = beanFactory。getBeansOfType(BeanPostProcessor。class); for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap。values()) { beanFactory。addBeanPostProcessor(beanPostProcessor); } } //。。。 getBean、getBeansOfType、getBeanDefinitionNames 方法}

AbstractApplicationContext 繼承 DefaultResourceLoader 是為了處理

spring。xml

配置資源的載入。

之後是在 refresh() 定義實現過程,包括:

提前例項化單例Bean物件

BeanPostProcessor 需要提前於其他 Bean 物件例項化之前執行註冊操作

在 Bean 例項化之前,執行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context。)

獲取 BeanFactory

建立 BeanFactory,並載入 BeanDefinition

另外把定義出來的抽象方法,refreshBeanFactory()、getBeanFactory() 由後面的繼承此抽象類的其他抽象類實現。

6。 獲取Bean工廠和載入資源

cn.bugstack.springframework.context.support.AbstractRefreshableApplicationContext

publicabstractclassAbstractRefreshableApplicationContextextendsAbstractApplicationContext{ private DefaultListableBeanFactory beanFactory; @OverrideprotectedvoidrefreshBeanFactory()throws BeansException { DefaultListableBeanFactory beanFactory = createBeanFactory(); loadBeanDefinitions(beanFactory); this。beanFactory = beanFactory; } private DefaultListableBeanFactory createBeanFactory(){ returnnew DefaultListableBeanFactory(); } protectedabstractvoidloadBeanDefinitions(DefaultListableBeanFactory beanFactory); @Overrideprotected ConfigurableListableBeanFactory getBeanFactory(){ return beanFactory; }}

在 refreshBeanFactory() 中主要是獲取了

的例項化以及對資源配置的載入操作

loadBeanDefinitions(beanFactory)

,在載入完成後即可完成對 spring。xml 配置檔案中 Bean 物件的定義和註冊,同時也包括實現了介面 BeanFactoryPostProcessor、BeanPostProcessor 的配置 Bean 資訊。

但此時資源載入還只是定義了一個抽象類方法

loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

,繼續由其他抽象類繼承實現。

7。 上下文中對配置資訊的載入

cn.bugstack.springframework.context.support.AbstractXmlApplicationContext

publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableApplicationContext{ @OverrideprotectedvoidloadBeanDefinitions(DefaultListableBeanFactory beanFactory){ XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this); String[] configLocations = getConfigLocations(); if (null != configLocations){ beanDefinitionReader。loadBeanDefinitions(configLocations); } } protectedabstract String[] getConfigLocations();}

在 AbstractXmlApplicationContext 抽象類的 loadBeanDefinitions 方法實現中,使用 XmlBeanDefinitionReader 類,處理了關於 XML 檔案配置資訊的操作。

同時這裡又留下了一個抽象類方法,getConfigLocations(),此方法是為了從入口上下文類,拿到配置資訊的地址描述。

8。 應用上下文實現類(ClassPathXmlApplicationContext)

cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext

publicclassClassPathXmlApplicationContextextendsAbstractXmlApplicationContext{ private String[] configLocations; publicClassPathXmlApplicationContext(){ } /** * 從 XML 中載入 BeanDefinition,並重新整理上下文 * * @param configLocations * @throws BeansException */publicClassPathXmlApplicationContext(String configLocations)throws BeansException { this(new String[]{configLocations}); } /** * 從 XML 中載入 BeanDefinition,並重新整理上下文 * @param configLocations * @throws BeansException */publicClassPathXmlApplicationContext(String[] configLocations)throws BeansException { this。configLocations = configLocations; refresh(); } @Overrideprotected String[] getConfigLocations() { return configLocations; }}

ClassPathXmlApplicationContext,是具體對外給使用者提供的應用上下文方法。

在繼承了 AbstractXmlApplicationContext 以及層層抽象類的功能分離實現後,在此類 ClassPathXmlApplicationContext 的實現中就簡單多了,主要是對繼承抽象類中方法的呼叫和提供了配置檔案地址資訊。

9。 在Bean建立時完成前置和後置處理

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

publicabstractclassAbstractAutowireCapableBeanFactoryextendsAbstractBeanFactoryimplementsAutowireCapableBeanFactory{ private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); @Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args)throws BeansException { Object bean = null; try { bean = createBeanInstance(beanDefinition, beanName, args); // 給 Bean 填充屬性 applyPropertyValues(beanName, bean, beanDefinition); // 執行 Bean 的初始化方法和 BeanPostProcessor 的前置和後置處理方法 bean = initializeBean(beanName, bean, beanDefinition); } catch (Exception e) { thrownew BeansException(“Instantiation of bean failed”, e); } addSingleton(beanName, bean); return bean; } public InstantiationStrategy getInstantiationStrategy(){ return instantiationStrategy; } publicvoidsetInstantiationStrategy(InstantiationStrategy instantiationStrategy){ this。instantiationStrategy = instantiationStrategy; } private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition){ // 1。 執行 BeanPostProcessor Before 處理 Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName); // 待完成內容:invokeInitMethods(beanName, wrappedBean, beanDefinition); invokeInitMethods(beanName, wrappedBean, beanDefinition); // 2。 執行 BeanPostProcessor After 處理 wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName); return wrappedBean; } privatevoidinvokeInitMethods(String beanName, Object wrappedBean, BeanDefinition beanDefinition){ } @Overridepublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor。postProcessBeforeInitialization(result, beanName); if (null == current) return result; result = current; } return result; } @Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor。postProcessAfterInitialization(result, beanName); if (null == current) return result; result = current; } return result; }}

實現 BeanPostProcessor 介面後,會涉及到兩個介面方法,

,分別作用於 Bean 物件執行初始化前後的額外處理。

也就是需要在建立 Bean 物件時,在 createBean 方法中新增

initializeBean(beanName, bean, beanDefinition);

操作。而這個操作主要主要是對於方法

applyBeanPostProcessorsBeforeInitialization

applyBeanPostProcessorsAfterInitialization

的使用。

另外需要提一下,applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization 兩個方法是在介面類

AutowireCapableBeanFactory

中新增加的。

五、測試

1。 事先準備

cn.bugstack.springframework.test.bean.UserDao

publicclassUserDao{ privatestatic Map hashMap = new HashMap<>(); static { hashMap。put(“10001”, “小傅哥”); hashMap。put(“10002”, “八杯水”); hashMap。put(“10003”, “阿毛”); } public String queryUserName(String uId){ return hashMap。get(uId); }}

cn.bugstack.springframework.test.bean.UserService

publicclassUserService{ private String uId; private String company; private String location; private UserDao userDao; publicvoidqueryUserInfo(){ return userDao。queryUserName(uId); } // 。。。get/set}

Dao、Service,是我們平常開發經常使用的場景。在 UserService 中注入 UserDao,這樣就能體現出Bean屬性的依賴了。

另外這裡新增加了 company、location,兩個屬性資訊,便於測試 BeanPostProcessor、BeanFactoryPostProcessor 兩個介面對 Bean 屬性資訊擴充套件的作用。

2。 實現 BeanPostProcessor 和 BeanFactoryPostProcessor

cn.bugstack.springframework.test.common.MyBeanFactoryPostProcessor

publicclassMyBeanFactoryPostProcessorimplementsBeanFactoryPostProcessor{ @OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException { BeanDefinition beanDefinition = beanFactory。getBeanDefinition(“userService”); PropertyValues propertyValues = beanDefinition。getPropertyValues(); propertyValues。addPropertyValue(new PropertyValue(“company”, “改為:位元組跳動”)); }}

cn.bugstack.springframework.test.common.MyBeanPostProcessor

publicclassMyBeanPostProcessorimplementsBeanPostProcessor{ @Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException { if (“userService”。equals(beanName)) { UserService userService = (UserService) bean; userService。setLocation(“改為:北京”); } return bean; } @Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException { return bean; }}

如果你在 Spring 中做過一些元件的開發那麼一定非常熟悉這兩個類,本文的測試也是實現了這兩個類,對例項化過程中的 Bean 物件做一些操作。

3。 配置檔案

基礎配置,無BeanFactoryPostProcessor、BeanPostProcessor,實現類

<?xml version=“1。0” encoding=“UTF-8”?>

增強配置,有BeanFactoryPostProcessor、BeanPostProcessor,實現類

<?xml version=“1。0” encoding=“UTF-8”?>

這裡提供了兩個配置檔案,一個是不包含BeanFactoryPostProcessor、BeanPostProcessor,另外一個是包含的。之所以這樣配置主要對照驗證,在運用 Spring 新增加的應用上下文和不使用的時候,都是怎麼操作的。

4。 不用應用上下文

@Testpublicvoidtest_BeanFactoryPostProcessorAndBeanPostProcessor(){ // 1。初始化 BeanFactory DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 2。 讀取配置檔案&註冊Bean XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader。loadBeanDefinitions(“classpath:spring。xml”); // 3。 BeanDefinition 載入完成 & Bean例項化之前,修改 BeanDefinition 的屬性值 MyBeanFactoryPostProcessor beanFactoryPostProcessor = new MyBeanFactoryPostProcessor(); beanFactoryPostProcessor。postProcessBeanFactory(beanFactory); // 4。 Bean例項化之後,修改 Bean 屬性資訊 MyBeanPostProcessor beanPostProcessor = new MyBeanPostProcessor(); beanFactory。addBeanPostProcessor(beanPostProcessor); // 5。 獲取Bean物件呼叫方法 UserService userService = beanFactory。getBean(“userService”, UserService。class); String result = userService。queryUserInfo(); System。out。println(“測試結果:” + result);}

DefaultListableBeanFactory 建立 beanFactory 並使用 XmlBeanDefinitionReader 載入配置檔案的方式,還是比較熟悉的。

接下來就是對 MyBeanFactoryPostProcessor 和 MyBeanPostProcessor 的處理,一個是在BeanDefinition 載入完成 & Bean例項化之前,修改 BeanDefinition 的屬性值,另外一個是在Bean例項化之後,修改 Bean 屬性資訊。

測試結果

透過測試結果可以看到,我們配置的屬性資訊已經與 spring。xml 配置檔案中不一樣了。

5。 使用應用上下文

@Testpublicvoidtest_xml(){ // 1。初始化 BeanFactory ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(“classpath:springPostProcessor。xml”); // 2。 獲取Bean物件呼叫方法 UserService userService = applicationContext。getBean(“userService”, UserService。class); String result = userService。queryUserInfo(); System。out。println(“測試結果:” + result);}

另外使用新增加的 ClassPathXmlApplicationContext 應用上下文類,再操作起來就方便多了,

這才是面向使用者使用的類

,在這裡可以一步把配置檔案交給 ClassPathXmlApplicationContext,也不需要管理一些自定義實現的 Spring 介面的類。

這與不用應用上下文的測試結果是一樣,不過現在的方式更加方便了。

六、總結

本文主要新增了 Spring 框架中兩個非常重要的介面 BeanFactoryPostProcess、BeanPostProcessor 同時還添加了關於應用上下文的實現,ApplicationContext 介面的定義是繼承 BeanFactory 外新增加功能的介面,它可以滿足於自動識別、資源載入、容器事件、監聽器等功能,同時例如一些國際化支援、單例Bean自動初始化等,也是可以在這個類裡實現和擴充的。

透過本文的實現一定會非常瞭解 BeanFactoryPostProcess、BeanPostProcessor,以後再做一些關於 Spring 中介軟體的開發時,如果需要用到 Bean 物件的獲取以及修改一些屬性資訊,那麼就可以使用這兩個介面了。同時 BeanPostProcessor 也是實現 AOP 切面技術的關鍵所在。

有人問:

面試問那麼多,可是工作又用不到,是嘎哈麼呢?

,嘎哈麼,那你說你開車上橋的時候,會每次都撞兩邊的護欄嗎,不撞是吧,那不要修了哇,直接就鋪一個平板,還省材料了。其實核心技術的原理學習,是更有助於你完成更復雜的架構設計,當你的知識能更全面覆蓋所承接的需求時,也就能更好的做出合理的架構和落地。

推薦文章

  • 國道315|孤獨、驚喜、壯美

    第六站茫崖翡翠湖,鑲嵌在戈壁的碧玉,多年開採形成的人工鹽湖,深深淺淺的鹽形成不一樣的坑,總面積26平方公里,鹽床淡青、翠綠或者深藍交替,形成一塊塊翡翠田園...

  • 這才是中年女人該有的秋季穿搭:“膝下裙+裸靴”,優雅又得體

    這才是中年女人該有的秋季穿搭:“膝下裙+裸靴”,優雅又得體要想把膝下裙+裸靴搭配得出色,你需要注意這些方面:tips1:在搭配上要把腰線凸顯出來不管你是高個子還是矮個子,也不管你的身材是胖是瘦,在面對大部分的穿搭組合的時候,都要儘量把腰線凸顯出來,這樣才能更好的修飾我們的身材,不至於讓整體的loo...

  • “吃雞”遊戲大變樣,玩家建房、睡雙人床,明日之後:你禮貌嗎?

    “吃雞”遊戲大變樣,玩家建房、睡雙人床,明日之後:你禮貌嗎?歡迎諸位小夥伴們來到天哥開講的《和平精英》“精英小課堂”~在很多老玩家的印象裡,這款遊戲一直都以“競技”為主,即便是如今出現了太多的面板,但核心玩法並沒有太大的變化~但是接下來的新模式,卻讓玩家有一種“穿越感”,甚至產生“進錯了遊戲”的感覺...