全國(guó)咨詢(xún)/投訴熱線:400-618-4000

首頁(yè)技術(shù)文章正文

IOC底層實(shí)現(xiàn)原理介紹,手動(dòng)實(shí)現(xiàn)IOC容器

更新時(shí)間:2020-08-14 來(lái)源:黑馬程序員 瀏覽量:

面試官特別愛(ài)問(wèn)SpringIOC底層實(shí)現(xiàn),Spring源碼晦澀難懂怎么辦呢? 跟著老師手動(dòng)實(shí)現(xiàn)一個(gè)mini ioc容器吧,實(shí)現(xiàn)后再回頭看Spring源碼事半功倍哦,就算直接和面試官講也完全可以哦,類(lèi)名完全按照源碼設(shè)計(jì),話不多說(shuō)開(kāi)干~!

手動(dòng)實(shí)現(xiàn)IOC容器的設(shè)計(jì)

需要實(shí)現(xiàn)的IOC功能:

·可以通過(guò)xml配置bean信息

·可以通過(guò)容器getBean獲取對(duì)象

·能夠根據(jù)Bean的依賴(lài)屬性實(shí)現(xiàn)依賴(lài)注入

·可以配置Bean的單例多例

實(shí)現(xiàn)簡(jiǎn)易IOC設(shè)計(jì)的類(lèi)

類(lèi)/接口說(shuō)明
BeanFactoryIOC容器的基礎(chǔ)接口,提供IOC容器的基本功能
DefaultListableBeanFactoryIOC容器的核心實(shí)現(xiàn)類(lèi),提供多個(gè)map集合用來(lái)存儲(chǔ)bean的定義對(duì)象,提供getBean方法的核心實(shí)現(xiàn)
XmlBeanFactoryIOC容器的實(shí)現(xiàn)類(lèi),基于xml構(gòu)建bean信息
XmlBeanDefinitionReader用于解析xml信息,并提供解析Document文檔的方法,并將解析到的BeanDefinition對(duì)象注冊(cè)到核心容器中
BeanDefinition封裝Bean的定義對(duì)象,如: bean的id class,scope ..等等
Property封裝Bean所關(guān)聯(lián)依賴(lài)的屬性


類(lèi)之間關(guān)系模型

1597377196425_IOC01.jpg


前期準(zhǔn)備

創(chuàng)建maven項(xiàng)目引入依賴(lài)

<dependencies>
    <!-- 解析xml -->
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.1</version>
    </dependency>
    <!-- BeanUtils    -->
    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
        <version>1.9.3</version>
    </dependency>
</dependencies>


準(zhǔn)備3個(gè)bean的實(shí)體類(lèi)

/**
 * 學(xué)生類(lèi)  
 * 學(xué)生類(lèi)依賴(lài)班級(jí)對(duì)象
 * 并提供 sayHello() 方法
 * @作者 itcast
 * @創(chuàng)建日期 2020/3/7 19:46
 **/
public class Student {
    private String name;
    private TClass tClass;
    public void sayHello(){
        System.out.println("大家好,我是" +this.name+" 我的班級(jí)是==>"+tClass.getCname() + " 我的老師是"+tClass.getTeacher().getTname());
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public TClass gettClass() {
        return tClass;
    }
    public void settClass(TClass tClass) {
        this.tClass = tClass;
    }
}
/**
 * 班級(jí)類(lèi)
 * 班級(jí)類(lèi)依賴(lài)教師對(duì)象
 * @作者 itcast
 * @創(chuàng)建日期 2020/3/7 19:45
 **/
public class TClass {
    private String cname;// 班級(jí)名稱(chēng)
    private Teacher teacher; // 老師
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
    public com.itcast.ioc.bean.Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(com.itcast.ioc.bean.Teacher teacher) {
        this.teacher = teacher;
    }
}
/**
 * 教師類(lèi)
 * @作者 itcast
 * @創(chuàng)建日期 2020/3/7 19:44
 **/
public class Teacher {
    private String tname;// 老師名稱(chēng)
    public String getTname() {
        return tname;
    }
    public void setTname(String tname) {
        this.tname = tname;
    }
}


xml配置對(duì)象

配置學(xué)生對(duì)象: 小明

依賴(lài)班級(jí)對(duì)象: 3年2班

依賴(lài)教師對(duì)象: 陳老師

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!-- 配置IOC容器要管理的對(duì)象   bean作用域: 單例  原型 -->
    <bean id="student" class="com.itcast.ioc.bean.Student" scope="singleton" lazy-init="true">
        <!-- 依賴(lài)注入:   屬性注入    構(gòu)造器注入   注解注入-->
        <property name="name" value="小明"></property>
        <property name="tClass" ref="tclass"></property>
    </bean>
    <bean id="tclass" class="com.itcast.ioc.bean.TClass">
        <property name="cname" value="3年2班"></property>
        <property name="teacher" ref="teacher"></property>
    </bean>
    <bean id="teacher" class="com.itcast.ioc.bean.Teacher">
        <property name="tname" value="陳老師"></property>
    </bean>
</beans>

mini-IOC容器-定義類(lèi)

定義BeanFactory

/**
 * 容器的基礎(chǔ)接口
 * 提供容器最基本的功能
 */
public interface BeanFactory {
    // 核心方法 獲取對(duì)象
    Object getBean(String beanName);
}


定義DefaultListableBeanFactory

package com.itcast.ioc.core;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 基礎(chǔ)容器的核心實(shí)現(xiàn)
 * 提供 beanDefinitionMap 存儲(chǔ)bean的定義
 * 提供 singletonObjects 存儲(chǔ)bean的對(duì)象實(shí)例
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:37
 **/
public class DefaultListableBeanFactory implements BeanFactory {
    // 提供 beanDefinitionMap 存儲(chǔ)bean的定義
    private Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    // 提供 singletonObjects 存儲(chǔ)bean的對(duì)象實(shí)例 (scope為singleton的)
    private Map<String,Object> singletonObjects = new ConcurrentHashMap<>();
    /**
     * 實(shí)現(xiàn)getBean方法
     * @param beanName
     * @return
     */
    @Override
    public Object getBean(String beanName) {
        return null;
    }
    /**
     * 將bean注冊(cè)到容器中
     * @param beanDefinition
     */
    public void registerBeanDefinition(BeanDefinition beanDefinition){
        beanDefinitionMap.put(beanDefinition.getBeanName(),beanDefinition);
    }
}


定義BeanDefnition

/**
 * 用于描述Bean的定義
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:41
 **/
public class BeanDefinition {
    private String beanName; // bean標(biāo)簽的ID 作為bean的唯一標(biāo)識(shí)
    private String className; // bean的所屬class
    private String scope = "singleton";  // bean的scope作用域
    private List<Property> propertyList = new ArrayList<>();
    public String getBeanName() {
        return beanName;
    }
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
    public String getScope() {
        return scope;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
    public List<Property> getPropertyList() {
        return propertyList;
    }
    public void setPropertyList(List<Property> propertyList) {
        this.propertyList = propertyList;
    }
}


定義Property

/**
 * 用于封裝一個(gè)property標(biāo)簽
 * 屬性數(shù)據(jù)
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:44
 **/
public class Property {
    private String name; // 屬性名稱(chēng)
    private String value; // 屬性的值
    private String ref; // 屬性的引用
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public String getRef() {
        return ref;
    }
    public void setRef(String ref) {
        this.ref = ref;
    }
}


定義XmlBeanFactory

/**
 * 繼承核心實(shí)現(xiàn)類(lèi)
 * 基于xml配置bean的實(shí)現(xiàn)類(lèi)
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:47
 **/
public class XmlBeanFactory extends DefaultListableBeanFactory {
    /**
     * 將解析配置文件 注冊(cè)bean的所有工作交給reader對(duì)象
     */
    final XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(this);
    /**
     * 構(gòu)造器需要傳入xml配置文件
     * @param configPath
     */
    public XmlBeanFactory(String configPath) {
        // 使用reader對(duì)象 解析配置  注冊(cè)Bean
        this.xmlBeanDefinitionReader.loadBeanDefinitions(configPath);
    }
}


定義XmlBeanDefinitionReader

/**
 * 解析配置
 * 注冊(cè)到容器中
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:51
 **/
public class XmlBeanDefinitionReader {
    // 核心beanfactory對(duì)象 用于將解析后的bean注冊(cè)到beanfactory中
    final DefaultListableBeanFactory beanFactory;
    public XmlBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
    /**
     * 根據(jù)傳遞的配置文件
     * 解析配置
     * 注冊(cè)bean
     * @param configPath
     */
    void loadBeanDefinitions(String configPath){

    }
}

mini-IOC容器--解析注冊(cè)

實(shí)現(xiàn)步驟

1. 通過(guò)dom4j解析xml得到Document文檔

2. 遍歷文檔所有Bean標(biāo)簽

3. 解析每一個(gè)Bean標(biāo)簽 封裝一個(gè)BeanDefinition對(duì)象

4. 解析每一個(gè)Bean標(biāo)簽下的所有Property標(biāo)簽 封裝一個(gè)Property對(duì)象

5. 將BeanDefinition和Property對(duì)象注冊(cè)到容器

實(shí)現(xiàn)xml解析及bean注冊(cè)

/**
 * 解析配置
 * 注冊(cè)到容器中
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:51
 **/
public class XmlBeanDefinitionReader {
    // 核心beanfactory對(duì)象 用于將解析后的bean注冊(cè)到beanfactory中
    final DefaultListableBeanFactory beanFactory;
    public XmlBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
    /**
     * 根據(jù)傳遞的配置文件
     * 解析配置
     * 注冊(cè)bean
     * @param configPath
     */
    void loadBeanDefinitions(String configPath){
        // 1. 通過(guò)dom4j解析xml得到Document文檔
        Document document = doLoadDocument(configPath);
        // 2. 遍歷文檔所有Bean標(biāo)簽
        Element rootElement = document.getRootElement();
        List<Element> list = rootElement.selectNodes("//bean");
        for (Element element : list) {
            // 3. 解析每一個(gè)Bean標(biāo)簽 封裝一個(gè)BeanDefinition對(duì)象
            BeanDefinition beanDefinition = parseBeanDefinition(element);
            // 5. 將BeanDefinition和Property對(duì)象注冊(cè)到容器
            beanFactory.registerBeanDefinition(beanDefinition);
        }
    }
    /**
     * 3. 解析每一個(gè)Bean標(biāo)簽 封裝一個(gè)BeanDefinition對(duì)象
     * 4. 解析每一個(gè)Bean標(biāo)簽下的所有Property標(biāo)簽 封裝一個(gè)Property對(duì)象
     */
    BeanDefinition parseBeanDefinition(Element element){
        BeanDefinition beanDefinition = new BeanDefinition();
        String beanName = element.attributeValue("id");
        String className = element.attributeValue("class");
        String scope = element.attributeValue("scope");
        beanDefinition.setBeanName(beanName);
        beanDefinition.setClassName(className);
        if(scope!=null&&!"".equals(scope)){
            beanDefinition.setScope(scope);
        }
        List<Element> propertyList = element.elements("property");
        for (Element propertyEle : propertyList) {
            Property property = new Property();
            property.setName(propertyEle.attributeValue("name"));
            property.setValue(propertyEle.attributeValue("value"));
            property.setRef(propertyEle.attributeValue("ref"));
            beanDefinition.getPropertyList().add(property);
        }
        return beanDefinition;
    }
    /**
     * 解析Document文檔
     * @param configPath
     * @return
     */
    Document doLoadDocument(String configPath){
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(configPath);
        SAXReader saxReader = new SAXReader();
        try {
            return saxReader.read(inputStream);
        } catch (DocumentException e) {
            e.printStackTrace();
            System.out.println("解析xml出現(xiàn)異常==>"+e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }
}


準(zhǔn)備測(cè)試類(lèi)

/**
 * 測(cè)試類(lèi)
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 16:19
 **/
public class IocTest {
    public static void main(String[] args) {
        // 創(chuàng)建IOC容器
        BeanFactory beanFactory = new XmlBeanFactory("applicationContext.xml");
        // 通過(guò)容器獲取對(duì)象
        Student student = (Student)beanFactory.getBean("student");
        // 調(diào)用對(duì)象sayHello方法
        student.sayHello();
    }
}


斷點(diǎn)查看注冊(cè)情況

可以看到我們配置的xml內(nèi)容 已經(jīng)解析成了BeanDefinition對(duì)象,注冊(cè)到了核心容器的map中

1597377245545_IOC02.jpg


mini-IOC容器-getBean

實(shí)現(xiàn)步驟

1. 先從單例的map集合中獲取 是否有指定beanName的對(duì)象

    ·有直接返回

    ·沒(méi)有下一步

2. 從注冊(cè)集合中獲取bean的定義對(duì)象

    ·有下一步

    ·沒(méi)有拋異常NoSuchBeanDefinition

3. 判斷bean的scope作用域

   singleton單例

       · createBean對(duì)象

        ·存入單例集合

        ·返回對(duì)象

prototype多例

        ·createBean對(duì)象

        ·返回對(duì)象

4. createBean方法

        獲取BeanDefinition中的className

        通過(guò)反射API得到Class對(duì)象

        通過(guò)反射API得到bean實(shí)例

        獲取BeanDefinition中依賴(lài)的屬性列表

        實(shí)現(xiàn)屬性的依賴(lài)注入

實(shí)現(xiàn)getBean及createBean方法

/**
 * 基礎(chǔ)容器的核心實(shí)現(xiàn)
 * 提供 beanDefinitionMap 存儲(chǔ)bean的定義
 * 提供 singletonObjects 存儲(chǔ)bean的對(duì)象實(shí)例
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:37
 **/
public class DefaultListableBeanFactory implements BeanFactory {
    // 提供 beanDefinitionMap 存儲(chǔ)bean的定義
    private Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    // 提供 singletonObjects 存儲(chǔ)bean的對(duì)象實(shí)例 (scope為singleton的)
    private Map<String,Object> singletonObjects = new ConcurrentHashMap<>();
    /**
     * 實(shí)現(xiàn)getBean方法
     * @param beanName
     * @return
     */
    @Override
    public Object getBean(String beanName) {
//        1. 先從單例的map集合中獲取 是否有指定beanName的對(duì)象
        Object singletonObj = singletonObjects.get(beanName);
//                有直接返回
        if(singletonObj!=null){
            return singletonObj;
        }
//                沒(méi)有下一步
//        2. 從注冊(cè)集合中獲取bean的定義對(duì)象
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//                有下一步
//        沒(méi)有拋異常NoSuchBeanDefinition
        if(beanDefinition==null){
            throw new RuntimeException("NoSuchBeanDefinition : 你找的 "+beanName+" 對(duì)象 不存在");
        }
//        3. 判斷bean的scope作用域
        String scope = beanDefinition.getScope();
//                singleton單例
        if("singleton".equals(scope)){
//        createBean對(duì)象
            Object obj = createBean(beanDefinition);
//        存入單例集合
            singletonObjects.put(beanName,obj);
//        返回對(duì)象
            return obj;
        }else {
//        prototype多例
//        createBean對(duì)象
            return createBean(beanDefinition);
//        返回對(duì)象
        }
    }
    /**
     * //4. createBean方法
     * //獲取BeanDefinition中的className
     * //通過(guò)反射API得到Class對(duì)象
     * //通過(guò)反射API得到bean實(shí)例
     * //獲取BeanDefinition中依賴(lài)的屬性列表
     * //實(shí)現(xiàn)屬性的依賴(lài)注入
     * 創(chuàng)建對(duì)象
     * @param beanDefinition
     * @return
     */
    Object createBean(BeanDefinition beanDefinition){
        String className = beanDefinition.getClassName();
        Class<?> aClass;
        try {
            aClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("類(lèi)未找到"+e.getMessage());
        }
        // 創(chuàng)建對(duì)象:
        Object obj;
        try {
            obj = aClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
            throw new RuntimeException("創(chuàng)建對(duì)象失敗"+e.getMessage());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new RuntimeException("非法訪問(wèn)"+e.getMessage());
        }
        // 依賴(lài)注入
        List<Property> propertyList = beanDefinition.getPropertyList();
        for (Property property : propertyList) {
            String name = property.getName();
            String value = property.getValue();
            String ref = property.getRef();
            // 屬性名不為空 進(jìn)行注入
            if(name!=null&&!"".equals(name)){
                // 如果配置的是value值 直接注入
                if(value!=null&&!"".equals(value)){
                    Map<String,String> params = new HashMap<>();
                    params.put(name,value);
                    try {
                        BeanUtils.populate(obj,params);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                        throw new RuntimeException("非法訪問(wèn)"+e.getMessage());
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                        throw new RuntimeException("調(diào)用目標(biāo)對(duì)象失敗"+e.getMessage());
                    }
                }
                // 如果配置的是ref需要獲取其它對(duì)象注入
                if(ref!=null&&!"".equals(ref)){
                    try {
                        BeanUtils.setProperty(obj,name,getBean(ref));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                        throw new RuntimeException("非法訪問(wèn)"+e.getMessage());
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                        throw new RuntimeException("調(diào)用目標(biāo)對(duì)象失敗"+e.getMessage());
                    }
                }
            }
        }
        return obj;
    }
    /**
     * 將bean注冊(cè)到容器中
     * @param beanDefinition
     */
    public void registerBeanDefinition(BeanDefinition beanDefinition){
        beanDefinitionMap.put(beanDefinition.getBeanName(),beanDefinition);
    }
}


mini-IOC容器-單例對(duì)象初始化

DefaultListableBeanFactory增加初始化方法

public void preInstaniceSingletons(){
        beanDefinitionMap.forEach((beanName,beanDefinition)->{
            String scope = beanDefinition.getScope();
            // 判斷單例  非抽象   不懶加載
            if("singleton".equals(scope)){
                this.getBean(beanName);
            }
        });
    }


XmlBeanFactory增加單例對(duì)象初始化

public XmlBeanFactory(String configPath) {
   // 使用reader對(duì)象 解析配置  注冊(cè)Bean
   this.xmlBeanDefinitionReader.loadBeanDefinitions(configPath);
   // 初始化單例對(duì)象
   this.preInstaniceSingletons();
}

mini-IOC容器-測(cè)試和小結(jié)

測(cè)試對(duì)象能否獲取

1597377257811_IOC03.jpg


查看bean的注冊(cè)及單例集合信息

可以通過(guò)變更scope的值查看對(duì)應(yīng)的變化

1597377267020_IOC04.jpg


IOC容器源碼及其它面試細(xì)節(jié)

擴(kuò)展: 容器如何創(chuàng)建對(duì)象

IOC容器在準(zhǔn)備創(chuàng)建對(duì)象時(shí), 會(huì)判斷是否有配置 factory-method方法

如果有配置 會(huì)調(diào)用factory-method所指向的方法構(gòu)建對(duì)象.

如果沒(méi)配置,會(huì)檢查是否有配置構(gòu)造參數(shù)

無(wú)構(gòu)造參數(shù): 調(diào)用默認(rèn)構(gòu)造器創(chuàng)建對(duì)象

有構(gòu)造參數(shù): 根據(jù)參數(shù)情況匹配對(duì)應(yīng)的構(gòu)造器

擴(kuò)展: bean的生命周期

spring 容器中的bean的完整生命周期一共分為十一步完成。

1.bean對(duì)象的實(shí)例化

2.封裝屬性,也就是設(shè)置properties中的屬性值

3.如果bean實(shí)現(xiàn)了BeanNameAware,則執(zhí)行setBeanName方法,也就是bean中的id值

4.如果實(shí)現(xiàn)BeanFactoryAware或者ApplicationContextAware ,需要設(shè)置setBeanFactory或者上下文對(duì)象setApplicationContext

5.如果存在類(lèi)實(shí)現(xiàn)BeanPostProcessor后處理bean,執(zhí)行postProcessBeforeInitialization,可以在初始化之前執(zhí)行一些方法

6.如果bean實(shí)現(xiàn)了InitializingBean,則執(zhí)行afterPropertiesSet,執(zhí)行屬性設(shè)置之后的操作

7.調(diào)用執(zhí)行指定的初始化方法

8.如果存在類(lèi)實(shí)現(xiàn)BeanPostProcessor則執(zhí)行postProcessAfterInitialization,執(zhí)行初始化之后的操作

9.執(zhí)行自身的業(yè)務(wù)方法

10.如果bean實(shí)現(xiàn)了DisposableBean,則執(zhí)行spring的的銷(xiāo)毀方法

11.調(diào)用執(zhí)行自定義的銷(xiāo)毀方法。

擴(kuò)展: bean的循環(huán)依賴(lài)問(wèn)題

A 依賴(lài) B B 依賴(lài) A 產(chǎn)生閉環(huán),稱(chēng)為循環(huán)依賴(lài)

·Spring 默認(rèn)允許單例對(duì)象的屬性注入 所產(chǎn)生的循環(huán)依賴(lài)

單例對(duì)象的循環(huán)依賴(lài) Spring通過(guò)3級(jí)緩存來(lái)解決

比如一個(gè)類(lèi)A中有一個(gè)屬性是B類(lèi),B類(lèi)中有一個(gè)屬性是A類(lèi),這時(shí)看Spring是怎么解決他們的相互依賴(lài)的。Spring注入一個(gè)類(lèi)的大體步驟分為兩部分,一是先完成對(duì)類(lèi)的構(gòu)造工作,二是會(huì)對(duì)類(lèi)的屬性進(jìn)行設(shè)置和填充。首先Spring構(gòu)造A類(lèi),通過(guò)AbstractAutowireCapableBeanFactory的doCreateBean方法中調(diào)用addSingletonFactory方法將A類(lèi)曝光到singletonFactories中。這時(shí)完成A的構(gòu)造后,需要填充B屬性,繼續(xù)第二步,發(fā)現(xiàn)B還沒(méi)有構(gòu)造,于是開(kāi)始B流程的構(gòu)造過(guò)程,構(gòu)造的時(shí)候發(fā)現(xiàn)需要填充A,從第三層緩存singletonFactories中找到A(此時(shí)的A還沒(méi)有完全構(gòu)造完成,但是可以拿到A的一個(gè)引用),B拿到A的引用后,完成B自己的填充屬性工作,完成初始化工作,把自己放到第一層緩存singletonObjects中。這時(shí)回到A的這邊,在拿到B對(duì)象后,完成自己的填充屬性工作。

源碼級(jí)別描述
singletonObjects一級(jí)緩存用于存放完全初始化好的 bean,從該緩存中取出的 bean 可以直接使用
earlySingletonObjects二級(jí)緩存存放原始的 bean 對(duì)象(尚未填充屬性),用于解決循環(huán)依賴(lài)
singletonFactories三級(jí)緩存存放 bean 工廠對(duì)象,用于解決循環(huán)依賴(lài)


·如果是構(gòu)造器依賴(lài)屬性 會(huì)報(bào)循環(huán)依賴(lài)異常

·如果對(duì)象都是多例對(duì)象 會(huì)報(bào)循環(huán)依賴(lài)異常

·如果設(shè)置allowCircularReferences為false 會(huì)報(bào)循環(huán)依賴(lài)異常

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
   if (this.allowBeanDefinitionOverriding != null) {
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   if (this.allowCircularReferences != null) {
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
}


擴(kuò)展: bean的覆蓋問(wèn)題

默認(rèn)情況:

同一個(gè)配置文件中出現(xiàn)id相同的bean會(huì)報(bào)錯(cuò),不同的配置文件出現(xiàn)id相同的bean后加,載的bean會(huì)將先加載的bean覆蓋掉稱(chēng)為bean的覆蓋,bean的覆蓋不會(huì)報(bào)錯(cuò),但可能影響我們的項(xiàng)目,可以通過(guò)屬性設(shè)置不允許bean的覆蓋,allowBeanDefinitionOverriding設(shè)置為false。

猜你喜歡:

Spring 核心 : IOC 處理器擴(kuò)展

java高級(jí)軟件工程課程

分享到:
在線咨詢(xún) 我要報(bào)名
和我們?cè)诰€交談!