spring ioc原理

原理:一般指的是代碼的實現 以及涉及到的技術 

一:以xml的形式來說 


1.主要涉及到xml解析技術 以及 反射機制 還有實例存儲的數據結構(容器) 
1)xml解析技術: 包括dom4j 以及jdom支持xpath… 功能更強大 推薦使用 
2)反射機制: 首先得獲得類的全路徑,該類還得有構造器,如果你要是寫了有參構造器的話,必須得顯示寫無參構造器。默認情況下,該類是自帶無參構造器。 
然後Class.forName(“xxx.xxx.xxx.User”).newInstance 會構建一個實例 利用無參構造器。 
3)容器: 
特點:根據唯一標示 獲取該實例 
容器底層的數據結構:採用Map集合構架承載實例與ID的角色 


二 :以註解的形式來說 


利用反射機制獲得註解 進行對該類實例化 
IOC 和 D I 
IOC:控制反轉 控制指的是什麼?反轉指的是什麼? 
控制:指的是構建實例的控制權 以前構建實例的權利由我們開發人員來new出來,包括依賴關係的注入,此時實例的控制權爲引用類,現在有了spring,構建實例的權利交給spring來接管,反轉控制就是反轉了對象的創建方式,從我們自己創建反轉給力程序(spring) 
反轉:控制權由其他類(引用類)轉爲spring了 
D I:依賴注入 依賴是什麼?注入又是什麼? 
依賴:指的是A類 要引用B類 那麼我們就說A依賴B 
注入:A既然依賴B 那麼B類何時初始化呢?爲了解決耦合度的問題 不能再A類中new B了 需要靠spring將B類的實例傳遞給A,該過程叫做注入 
耦合度問題:A依賴B才能完成特定的功能。該B爲一個藉口,實現類有多個Bimpl_1 Bimpl_2各有不同。 
以前A可以直接使用Bimpl_1 那麼我們就說A與Bimpl_1 緊密聯繫在一起了,耦合度很高 
現在A依賴Bimpl_1 的接口即B,B接口的實現由Spring來控制注入Bimpl_1 或者Bimpl_2.即A與Bimpl_1 實現瞭解耦(多態 多種形式表現) 
IOC 和 DI的區別: 
先有了IOC 將實例構建出來 才能DI,就是去ioc容器裏即concurrentHashMap里根據依賴類的 Bean 以 beanName 爲鍵去保存實例的HashMap 中去取該類的實例化對象,注入

(原來就這些,spring的代碼實現,看看下面的就好了,不用去費心記,你也記不住,沒必要,不過還是寫下,方便理解)

IOC容器的設計與實現

1,IoC容器設計中,兩個主要的接口

1)BeanFactory:可以理解爲IoC容器的抽象,提供了ioc容器的最基本API。
2)ApplicationContext:IoC容器的高級形態,在基礎IoC容器上加了許多特性。
從繼承圖來理解:

DefaultListableBeanFactory是IoC容器的最基礎實現,是一個最基礎最簡單的IoC容器對象,其高級容器ApplicationContext也是通過持有DefaultListableBeanFactory引用,在基礎IoC容器之上進行特性增強。

容器設計原理

XmlBeanFactory這個IoC容器便是在DefaultListableBeanFactory基礎容器之上,添加了如xml讀取的附加功能。
編程式使用IoC容器示例

ClassPathResource res = new ClassPathResource("bean.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);

大致過程如下幾步:
1)讀取bean.xml配置文件資源
2)創建基礎BeanFactory容器(DefaultListableBeanFactory)
3)創建資源讀取器(XmlBeanDefinitionReader),並將其與BeanFactory容器對象進行關聯
4)將bean.xml配置文件中的信息解析成BeanDefinition元數據信息對象,並註冊到BeanFactory(IoC容器)中

ApplicationContext容器特點

ApplicationContext通過對不同特性接口的實現爲基礎IoC容器添加了許多特性
1)MessageSource接口:支持不同的信息源。
2)ResourceLoader和Resource接口:支持從不同的途徑獲取資源信息。
3)ApplicationEventPublisher接口:支持應用事件。
4)ApplicationContext接口:在基本IoC容器基礎上增加附加服務。

IoC容器的初始化過程

IoC容器啓動的三個基本過程
1)Resource資源信息定位
2)BeanDefinition的載入(將資源中的信息初始化爲BeanDefinition對象)
3)向IoC容器註冊生成的BeanDefinition對象

下面我們通過FileSystemXmlApplicationContext爲例,進行IoC容器初始化過程的解析

 

FileSystemXmlApplicationContext是一個支持xml定義BeanDefinition的ApplicationContext,我們看一下
FileSystemXmlApplicationContext的具體實現

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

    public FileSystemXmlApplicationContext() {
    }

    public FileSystemXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }

    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, null);
    }

    public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
        this(configLocations, refresh, null);
    }

    // 調用refresh函數載入和註冊BeanDefinition對象,完成IoC容器的初始化過程
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
    // 構造一個FileSystemResource來獲取資源文件,此方法是在BeanDefinitionReader的loadBeanDefintion中被調用
    // loadBeanDefintion方法是一個抽象,具體的資源定位的實現由具體的子類來完成
    @Override
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }
}

這裏的refresh方法是IoC容器初始化的唯一入口
初始化調用過程大致如下:IoC容器執行refresh的過程

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 初始化準備工作
      prepareRefresh();
      // 獲取BeanFactory
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // BeanFactory的預準備工作
      prepareBeanFactory(beanFactory);

      try {
         // beanFactory準備工作完成之後進行的後置處理工作。
         postProcessBeanFactory(beanFactory);

         // 調用BeanFactoryPostProcessor各個實現類的postProcessFactory(factory)方法。
         invokeBeanFactoryPostProcessors(beanFactory);

         // 註冊BeanPostProcessor的實現類
         registerBeanPostProcessors(beanFactory);

         // 初始化當前ApplicationContext的MessageSource
         initMessageSource();

         //初始化ApplicationContext事件廣播器
         initApplicationEventMulticaster();

         // 鉤子方法,在這裏可以初始化一些特殊的bean
         onRefresh();

         // 註冊事件監聽器
         registerListeners();

         // 初始化所有的singleton beans
         finishBeanFactoryInitialization(beanFactory);

         //廣播初始化完成
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

其中最主要的BeanDefintion對象的載入和註冊過程是在
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()中refreshBeanFactory方法中完成

 @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 創建ioc容器
            // new DefaultListableBeanFactory(getInternalParentBeanFactory())
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            // 啓動BeanDefinition的載入和註冊過程
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

這裏的loadBeanDefinitions方法中會創建XmlBeanDefinitionReader對象,並啓動BeanDefinitionReader的getResourceLoader方法

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        // 以Resource的方式獲取配置文件的資源位置
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        // 以String的方式獲取配置文件的資源位置
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

BeanDefinitionReader抽象中會完成配置文件的資源的加載

 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int loadCount = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    for (Resource resource : resources) {
                        actualResources.add(resource);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }
                return loadCount;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            // 調用具體實現容器的getResourceByPath方法獲取Resource handle對象並根據具體實現加載配置資源
            Resource resource = resourceLoader.getResource(location);
            // 加載和註冊BeanDefinition元信息對象,具體由XmlBeanDefinitionReader實現
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
    }

XmlBeanDefinitionReader中loadBeanDefinitions的具體實現

 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            // 準備IO流來獲取配置資源中的數據
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

    /**
     * Actually load bean definitions from the specified XML file.
     * @param inputSource the SAX InputSource to read from
     * @param resource the resource descriptor for the XML file
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     * @see #doLoadDocument
     * @see #registerBeanDefinitions
     */
     // 真正開始從指定的資源文件中獲取信息,加載並註冊BeanDefinition到IoC中
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            // 通過DefaultDocumentLoader對象獲取xml配置文件的Document對象
            Document doc = doLoadDocument(inputSource, resource);
            // 將獲取的Document對象解析成BeanDefinition對象,並註冊到IoC容器中
            return registerBeanDefinitions(doc, resource);
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }

將獲取的Document對象解析成BeanDefinition對象的具體實現由BeanDefinitionParserDelegate解析器具體實現完成

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 將Document對象解析成BeanDefinition對象的具體方法
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                //將解析好的BeanDefinition註冊到DefaultListableBeanFactory容器對象中
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

具體的Document解析成BeanDefinition的過程是通過不斷的遞歸調用完成,具體實現這裏不做分析

public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));
        // 獲取定義的<bean>中設置的bean的name,設置到BeanDefinition對象中去
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }

        try {
            String parent = null;
            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                parent = ele.getAttribute(PARENT_ATTRIBUTE);
            }
            // 創建BeanDefinition對象
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 對bean元素的屬性進行解析
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

            parseMetaElements(ele, bd);
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            // 解析<bean>的構造函數設置
            parseConstructorArgElements(ele, bd);
            // 解析<bean>的property設置
            parsePropertyElements(ele, bd);
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            return bd;
        }
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }

而註冊則是將BeanDefinition對象放入到DefaultListableBeanFactory容器中維護的一個map中
this.beanDefinitionMap.put(beanName, beanDefinition);

至此,IoC容器的初始化過程就完成了。

總結:IoC容器的初始化過程就是將xml配置資源的信息抽象到BeanDefinition信息對象中,再將BeanDefinition設置到基本容器的map中,BeanDefinition中的信息是容器建立依賴反轉的基礎,IoC容器的作用就是對這些信息進行處理和維護。

IoC容器的依賴注入

依賴注入是用戶第一次向IoC容器索要Bean時觸發的,入口爲DefaultListableBeanFactory基類AbstractBeanFactory中的getBean方法

具體依賴注入過程

總結

Spring IOC容器主要有繼承體系底層的BeanFactory、高層的ApplicationContext和WebApplicationContext

Bean有自己的生命週期

容器啓動原理:Spring應用的IOC容器通過tomcat的Servlet或Listener監聽啓動加載;Spring MVC的容器由DispatchServlet作爲入口加載;Spring容器是Spring MVC容器的父容器

容器加載Bean原理:

BeanDefinitionReader讀取Resource所指向的配置文件資源,然後解析配置文件。配置文件中每一個解析成一個BeanDefinition對象,並保存到BeanDefinitionRegistry中;

容器掃描BeanDefinitionRegistry中的BeanDefinition;調用InstantiationStrategy進行Bean實例化的工作;使用BeanWrapper完成Bean屬性的設置工作;

單例Bean緩存池:Spring 在 DefaultSingletonBeanRegistry 類中提供了一個用於緩存單實例 Bean 的緩存器,它是一個用 HashMap 實現的緩存器,單實例的 Bean 以 beanName 爲鍵保存在這個HashMap 中。

spring的依賴注入原理

 

我們可以看出,對屬性的注入過程分以下兩種情況:
1)、屬性值類型不需要強制轉換時,不需要解析屬性值,直接準備進行依賴注入。
2)、屬性值需要進行類型強制轉換時,如對其他對象的引用等,首先需要解析屬性值,然後對解析後的屬性值進行依賴注入。
對屬性值的解析是在 BeanDefinitionValueResolver 類中的 resolveValueIfNecessary()方法中進行的,對屬性值的依賴注入是通過 bw.setPropertyValues()方法實現的,在分析屬性值的依賴注入之前,我們先分析一下對屬性值的解析過程 

解析屬性注入規則

當容器在對屬性進行依賴注入時,如果發現屬性值需要進行類型轉換,如屬性值是容器中另一個 Bean實例對象的引用,則容器首先需要根據屬性值解析出所引用的對象,然後才能將該引用對象注入到目標實例對象的屬性上去,對屬性進行解析的由 resolveValueIfNecessary()方法實現。

Spring IOC 容器是如何將屬性的值注入到 Bean 實例對象中去的:
1)、對於集合類型的屬性,將其屬性值解析爲目標類型的集合後直接賦值給屬性。
2)、對於非集合類型的屬性,大量使用了 JDK 的反射機制,通過屬性的 getter()方法獲取指定屬性注入以前的值,同時調用屬性的 setter()方法爲屬性設置注入後的值。看到這裏相信很多人都明白了 Spring的 setter()注入原理

依賴注入流程補充(這個比較細)

1、getBean第一次調用lazy-init的bean

      是以BeanFactory的getBean方法爲入口觸發的(實現在AbstractBeanFactory實現類中)。如果是單例會緩存起來只加載一次,如果是FactoryBean這種特殊的bean會把這個bean的實例傳入getObjectForBeanInstance方法獲得FactoryBean產生的bean(調用FactoryBean的getObject方法,這就是自定義的FactoryBean要重寫的方法,AOP也是這個原理,詳情見下方AOP分析)。在第一次載入時要先判斷這個BeanDefinition在當前BeanFactory有沒有,沒有就從雙親BeanFactory中找,一直遞歸。

      找到後要驗證是否存在遞歸依賴,有則報錯無則設置當前bean依賴bean的依賴關係到兩個map中(一個是被依賴map,一個是依賴map),其中:
      (1)如果是單例第一次載入就調用getSingleton方法(方法中回調了參數中ObjectFactory的getObject方法,這裏重寫了這個方法調用createBean)獲得實例用getObjectForBeanInstance獲得FactoryBean產生的bean(如果它是FactoryBean的話)。
      (2)如果是prototype加載調用createBean後調用getObjectForBeanInstance。
      (3)如果是其他scope類型:request、session和global session,這三種就用scope.get獲取實例(和getSingleton類似回調重寫的getObject也就是調用createBean)後調用getObjectForBeanInstance。

      最後如果getBean指定了requiredType要檢驗獲取的bean能不能轉化成指定的類型不能的話就報錯。

      createBean方法就是生成bean的方法並對一些比如init-method屬性、後置處理器等一些初始化進行了處理。方法中在實例化之前判斷是否有post-processor,如果有這樣的processor則短路指定bean的創建,直接返回一個proxy而不是指定的bean(這種processor可以指定生成一個其他類型的對象)沒有的話用doCreateBean創建bean返回。

      doCreateBean是用createBeanInstance生成BeanWrapper(包裝bean)之後用populateBean向其中的bean完成依賴bean的注入(autowire等)。

      createBeanInstance創建beanWrapper時分三類進行處理:
      (1)如果有工廠方法,調用instantiateUsingFactoryMethod創建。
      (2)如果是構造器注入的方式調用autowireConstructor。
      (3)簡單方式調用instantiateBean。調用的是策略類(默認SimpleInstantiationStrategy)的instantiate而其中又是通過bean方法是否有跟IOC容器同名的(會被覆蓋)來分兩類處理(沒同名方法的從BeanDefinition中拿出class直接用jdk的反射拿構造器來newinstance一個實例,如果有同名的則是用CGLIB的方式來new一個實例)。

      populateBean爲生成的bean依賴注入,先對非簡單類型屬性有autowire的進行處理,判斷這個屬性在之前解析載入beanDefinition時property裏有沒有,有的話進行getBean初始化後放入PropertyValue集合中(這個就是propertyname和value的封裝),然後更新依賴map,再對非autowire的或一般屬性進行注入,有要轉化的要經過valueResolver的轉化(如果是RuntimeBeanReference之前載入時XML中配置是ref的就getBean(如果在雙親BeanFactory中就從雙親中取)獲得後也放到PropertyValue集合中,也要更新依賴map)。最後再注入到bean中,這裏說的注入其實真實發生在最後的BeanWraper的setPropertyValue(propertyValue集合)方法,具體實現就是通過反射的方式獲得setter方法賦值。

2、lazy-init==false初始化(只對singleton,也是默認方式)

      在refresh方法中的finishBeanFactoryInitialization方法中進行初始化(實際也是調用getBean方法)。

IoC(控制反轉)思想(其實ioc是個思想)

控制反轉IoC(Inversion of Control)是說創建對象的控制權進行轉移,以前創建對象的主動權和創建時機是由自己把控的,而現在這種權力轉移到第三方,比如轉移交給了IoC容器,它就是一個專門用來創建對象的工廠,你要什麼對象,它就給你什麼對象,有了 IoC容器,依賴關係就變了,原先的依賴關係就沒了,它們都依賴IoC容器了,通過IoC容器來建立它們之間的關係

spring的ioc就是spring對ioc原理的實現,就是創建對象和索取對象都交給了ioc容器。就是通過bean初始化入後refresh()方法入口,進行一系列的處理,最終通過beanName這一屬性,反射實例化bean對象,在放到concurrentHashMap中緩存起來,這裏可以看出spring的ioc容器就是個map-存儲bean信息的map,用的時候,通過beanName去獲取bean,這裏需要注意,通過beanName獲取bean的時候,是已經初始化的,沒初始化的,還要走一邊bean的初始化流程

 

 

 

 

 

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