【源碼Spring系列】——IOC設計理念以及自動裝配原理

        凡是使用Spring的開發者都知道Spring中兩大核心IOC和AOP,要問這兩點,一般都會說IOC實現控制反轉,AOP實現了面向切面編程。本文主要講解IOC,所以深入提問IOC歸根結底解決的是什麼問題,通過何種方式實現,控制反轉是從何方轉向何處呢?IOC和DI有什麼關係?

沒有IOC時,開發是什麼樣子?

當項目比較龐大的時候,這種開發存在什麼問題?

1、上面案例中D會被重複創建

2、對象創建過程引用其他類多的情況時,對象缺少管理

3、從UML來講,A 和 B、D的關係是組合關係,不可分割,屬於強耦合關係。現實中B、D可能在A中發揮價值不大,並不是不可分割的關係,可能聚合關係更適合

在沒有IOC的時候,怎麼解決上述問題呢?

1、組合關係改成聚合關係,利用set,屬性,構造器方式實現

2、利用單例模式,防止對象被重複創建

3、利用抽象工廠模式,使用反射機制,管理對象的創建

說的這些解決方案,其實基本上就是IOC最基礎的原理了。這也爲什麼單例設計模式,以及反射,工廠模式等在面試中額外重要的原因。

IOC容器的設計理念

This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.

IoC(Inversion of Control) 也稱爲依賴注入(dependency injection, DI)。它是一個對象定義依賴關係的過程,也就是說,對象只通過構造函數參數、工廠方法的參數或對象實例構造或從工廠方法返回後在對象實例上設置的屬性來定義它們所使用的其他對象。然後容器在創建bean時注入這些依賴項。這個過程基本上是bean的逆過程,因此稱爲控制反轉(IoC)。

在Spring中,構成應用程序主幹並由Spring IoC容器管理的對象稱爲bean。bean是由Spring IoC容器 實例化、組裝和管理的對象。

IoC容器設計理念:通過容器統一對象的構建方式,並且自動維護對象的依賴關係。

結合上面的例子來闡述爲什麼是控制反轉。例子中B的創建是因爲A主動new,如果放到Spring中,利用IOC,IOC容器不管是否依賴關係,將所有可用裝配的bean都放到容器中,B對象的創建從A改爲由IOC創建,創建的控制權反轉了。控制反轉,說到底由對象自身決定,B是否可以創建,不會再因爲A中是否存在new而決定。一般通常配合出現的還有DI依賴注入,A需B怎麼辦,依賴注入。A在容器中拿到B,進而可以正常使用。

上面例子使用IOC之後的關係圖

PS:注意分區兩圖中箭頭的方向,圖1中是被動創建,圖2中是主動注入

回答下開頭的問題

1、控制反轉是從何方轉向何處 ?

對象從被其他使用而創建,改爲主動創建。如果其他對象需要,依靠的DI,從容器中拿取

2、IOC和DI有什麼關係?

IOC是設計思想,那麼DI依賴注入就是IOC的實現,如果A無法拿到B,那麼程序是無法正常運行的。所以IOC和DI總是一起出現的。

IOC的應用——bean是如何裝配到容器中的?

早期bean的裝配方式 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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user"  class="mandy.spring.com.bean.User" />
</beans>
 @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println(context.getBean("user"));
    }

最後的表現就是通過xml創建了一個user對象,那麼在spring中整個創建過程是如何呢?

圖解自動裝配原理

模擬自動裝配代碼流程

@Test
    public void testXml() {
        //資源加載器
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        //獲取資源
        Resource resource = resourceLoader.getResource("spring.xml");

        //註冊器  
        //ioc最最最核心的類 DefaultListableBeanFactory
        BeanDefinitionRegistry registry = new DefaultListableBeanFactory();
        
        //讀取器
        BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);

        //讀取資源
        reader.loadBeanDefinitions(resource);

        //讀取到的資源bean
        for (String beanDefinitionName : registry.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        
        //反射創建bean user
        System.out.println(((DefaultListableBeanFactory) registry).getBean("user"));
    }

解釋下BeanDefinition是什麼?

在創建的bean的時候每個bean雖然都是Object,但是bean各自有些屬性,例如beanName,構造方法,scope等等,如何保證創建的每個bean與定義的相符呢?BeanDefinition就是用於存儲bean的元數據,最後反射創建就是BeanDefinition中存儲的元數據完成createBean。理論上Bean和BeanDefinition是一一對應的關係,即存在一個BeanDefinition則存在一個Bean對象,但是存在特殊情況,這個特殊情況會在後面的博客中更新(小神祕啊,連載記得追啊,😝)。

搞明白了BeanDefinition就理解爲什麼IOC過程中有個BeanDefinitionRegistry 註冊器,本質上就是管理BeanDefinition的CRUD。

總結

       IOC過程的本質其實很簡單,就是爲了解決對象管理問題,整個IOC過程中首先就是自動裝配,所謂裝配加載資源解析資源創建bean,然後整個過程就結束了。本文講解的IOC設計理念以及自動裝配的原理,但是除此之外Spring中還有很多內容值得去探索。bean的裝配方式,bean的創建過程是如何保證單例,在創建過程中經常遇到的BeanFactory和FactoryBean又有什麼不同,又是如何完成的依賴注入等等。所以一起學習喲!

                                                 漫漫長途,終有迴轉;餘味苦澀,終有回甘

                                                             Trying to light up the dark

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章