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

歡迎訪問 生活随笔!

生活随笔

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

javascript

从源码深处体验Spring核心技术--IOC容器初体验

發布時間:2024/4/13 javascript 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从源码深处体验Spring核心技术--IOC容器初体验 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

開局經驗之談:可能從這一篇文章開始,小伙伴們都會有點暈車的感覺了,但是這個系列并不是只是介紹下spring表面的一些膚淺的東西,本系列的目的是為了讓大家從源碼層次深入理解Spring,這也是大家在未來的求職道路上的一個重要的漲薪手段,希望小伙伴都不要放棄,結合源碼多看幾遍,努力一定會有收獲。

再談 IOC 與 DI

IOC(Inversion of Control)控制反轉:所謂控制反轉,就是把原先我們代碼里面需要實現的對象創建、依賴的代碼,反轉給容器來幫忙實現。那么必然的我們需要創建一個容器,同時需要一種描述來讓容器知道需要創建的對象與對象的關系。

這個描述最具體表現就是我們所看到的配置文件。

DI(Dependency Injection)依賴注入:就是指對象是被動接受依賴類而不是自己主動去找,換句話說就是指對象不是從容器中查找它依賴的類,而是在容器實例化對象的時候主動將它依賴的類注入給它。

先從我們自己設計這樣一個視角來考慮:

1、對象和對象的關系怎么表示?

可以用 xml,properties 文件等語義化配置文件表示。

2、描述對象關系的文件存放在哪里?

可能是 classpath,filesystem,或者是 URL 網絡資源,servletContext 等。

回到正題,有了配置文件,還需要對配置文件解析。

3、不同的配置文件對對象的描述不一樣,如標準的,自定義聲明式的,如何統一?

在內部需要有一個統一的關于對象的定義,所有外部的描述都必須轉化成統一的描述定義。

4、如何對不同的配置文件進行解析?

需要對不同的配置文件語法,采用不同的解析器。

Spring 核心容器類圖

1、BeanFactory

Spring Bean 的創建是典型的工廠模式,這一系列的 Bean 工廠,也即 IOC 容器為開發者管理對象間的依賴關系提供了很多便利和基礎服務,在 Spring 中有許多的 IOC 容器的實現供用戶選擇和使用,其相互關系如下:

其中 BeanFactory 作為最頂層的一個接口類,它定義了 IOC 容器的基本功能規范BeanFactory 有三 個重要的子類:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory。

但是從類圖中我們可以發現最終的默認實現類是 DefaultListableBeanFactory,它實現了所有的接口。

那為何要定義這么多層次的接口呢?

查閱這些接口的源碼和說明發現,每個接口都有它使用的場合,它主要是為了區分在 Spring 內部在操作過程中對象的傳遞和轉化過程時,對對象的數據訪問所做的限制。

例如 ListableBeanFactory 接口表示這些 Bean 是可列表化的,而 HierarchicalBeanFactory 表示的是這些 Bean 是有繼承關系的,也就是每個 Bean 有可能有父 Bean。

AutowireCapableBeanFactory 接口定義 Bean 的自動裝配規則。這三個接口共同定義了 Bean 的集合、Bean 之間的關系、以及 Bean 行為。

最基本的 IOC 容器接口 BeanFactory,來看一下它的源碼:

public interface BeanFactory { //對 FactoryBean 的轉義定義,因為如果使用 bean 的名字檢索 FactoryBean 得到的對象是工廠生成的對象, //如果需要得到工廠本身,需要轉義 String FACTORY_BEAN_PREFIX = "&"; //根據 bean 的名字,獲取在 IOC 容器中得到 bean 實例 Object getBean(String name) throws BeansException; //根據 bean 的名字和 Class 類型來得到 bean 實例,增加了類型安全驗證機制。 <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; //提供對 bean 的檢索,看看是否在 IOC 容器有這個名字的 bean boolean containsBean(String name); //根據 bean 名字得到 bean 實例,并同時判斷這個 bean 是不是單例 boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException; //得到 bean 實例的 Class 類型 @Nullable Class<?> getType(String name) throws NoSuchBeanDefinitionException;//得到 bean 的別名,如果根據別名檢索,那么其原名也會被檢索出來 String[] getAliases(String name); }

在 BeanFactory 里只對 IOC 容器的基本行為作了定義,根本不關心你的 Bean 是如何定義怎樣加載的。

正如我們只關心工廠里得到什么的產品對象,至于工廠是怎么生產這些對象的,這個基本的接口不關心。

而要知道工廠是如何產生對象的,我們需要看具體的 IOC 容器實現,Spring 提供了許多 IOC 容器的 實 現 。

比 如 GenericApplicationContext , ClasspathXmlApplicationContext 等 。

ApplicationContext 是 Spring 提供的一個高級的 IOC 容器,它除了能夠提供 IOC 容器的基本功能外,還為用戶提供了以下的附加服務。

從 ApplicationContext 接口的實現,我們看出其特點:

1、支持信息源,可以實現國際化。(實現 MessageSource 接口)

2、訪問資源。(實現 ResourcePatternResolver 接口,后面章節會講到)

3、支持應用事件。(實現 ApplicationEventPublisher 接口)

2、BeanDefinition

SpringIOC 容器管理了我們定義的各種 Bean 對象及其相互的關系,Bean 對象在 Spring 實現中是以 BeanDefinition 來描述的,其繼承體系如下:

3、BeanDefinitionReader

Bean 的解析過程非常復雜,功能被分的很細,因為這里需要被擴展的地方很多,必須保證有足夠的靈活性,以應對可能的變化。

Bean 的解析主要就是對 Spring 配置文件的解析。這個解析過程主要通過BeanDefintionReader 來完成,最后看看 Spring 中 BeanDefintionReader 的類結構圖:

通過本章內容的分析,我們對 Spring 框架體系有了一個基本的宏觀了解,希望小伙伴們好好理解,最好在腦海中形成畫面,為以后的學習打下良好的鋪墊。

Web IOC 容器初體驗

我們還是從大家最熟悉的 DispatcherServlet 開始,我們最先想到的還是 DispatcherServlet 的 init()方法。我們發現在 DispatherServlet 中并沒有找到 init()方法。

但是經過探索,往上追索在其父類HttpServletBean 中找到了我們想要的 init()方法,如下:

Web IOC 容器初體驗

我們還是從大家最熟悉的 DispatcherServlet 開始,我們最先想到的還是 DispatcherServlet 的 init()方法。我們發現在 DispatherServlet 中并沒有找到 init()方法。

但是經過探索,往上追索在其父類HttpServletBean 中找到了我們想要的 init()方法,如下:

@Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); }// Set bean properties from init parameters. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { //定位資源 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); //加載配置信息 ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); }catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); }throw ex; } }// Let subclasses do whatever initialization they like.initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }

在 init()方法中,真正完成初始化容器動作的邏輯其實在 initServletBean()方法中,我們繼續跟進initServletBean()中的代碼在 FrameworkServlet 類中:

protected final void initServletBean() throws ServletException { getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); if (this.logger.isInfoEnabled()) { this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started"); }long startTime = System.currentTimeMillis(); try { this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); }catch (ServletException ex) { this.logger.error("Context initialization failed", ex); throw ex; }catch (RuntimeException ex) { this.logger.error("Context initialization failed", ex); throw ex; }if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); } }

在上面的代碼中終于看到了我們似曾相識的代碼 initWebAppplicationContext(),繼續跟進:

從上面的代碼中可以看出,在 configAndRefreshWebApplicationContext()方法中,調用 refresh()方法,這個是真正啟動 IOC 容器的入口,后面會詳細介紹。

IOC 容器初始化以后,最后調用了DispatcherServlet 的 onRefresh()方法,在 onRefresh()方法中又是直接調用 initStrategies()方法初始化 SpringMVC 的九大組件:

?

總結

以上是生活随笔為你收集整理的从源码深处体验Spring核心技术--IOC容器初体验的全部內容,希望文章能夠幫你解決所遇到的問題。

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