教育行業(yè)A股IPO第一股(股票代碼 003032)

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

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

更新時(shí)間:2020年08月14日15時(shí)25分 來(lái)源:傳智播客 瀏覽次數(shù):

面試官特別愛(à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的依賴屬性實(shí)現(xiàn)依賴注入

·可以配置Bean的單例多例

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

類(lèi)/接口 說(shuō)明
BeanFactory IOC容器的基礎(chǔ)接口,提供IOC容器的基本功能
DefaultListableBeanFactory IOC容器的核心實(shí)現(xiàn)類(lèi),提供多個(gè)map集合用來(lái)存儲(chǔ)bean的定義對(duì)象,提供getBean方法的核心實(shí)現(xiàn)
XmlBeanFactory IOC容器的實(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)之間關(guān)系模型

1597377196425_IOC01.jpg

前期準(zhǔn)備

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


<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)依賴班級(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)依賴教師對(duì)象
 * @作者 itcast
 * @創(chuàng)建日期 2020/3/7 19:45
 **/
public class TClass {
    private String cname;// 班級(jí)名稱
    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;// 老師名稱
    public String getTname() {
        return tname;
    }
    public void setTname(String tname) {
        this.tname = tname;
    }
}


xml配置對(duì)象

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

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

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


<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!-- 配置IOC容器要管理的對(duì)象   bean作用域: 單例  原型 -->
    <bean id="studentclass="com.itcast.ioc.bean.Studentscope="singletonlazy-init="true">
        <!-- 依賴注入:   屬性注入    構(gòu)造器注入   注解注入-->
        <property name="namevalue="小明"></property>
        <property name="tClassref="tclass"></property>
    </bean>
    <bean id="tclassclass="com.itcast.ioc.bean.TClass">
        <property name="cnamevalue="3年2班"></property>
        <property name="teacherref="teacher"></property>
    </bean>
    <bean id="teacherclass="com.itcast.ioc.bean.Teacher">
        <property name="tnamevalue="陳老師"></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,BeanDefinitionbeanDefinitionMap = new ConcurrentHashMap<>();
    // 提供 singletonObjects 存儲(chǔ)bean的對(duì)象實(shí)例 (scope為singleton的)
    private Map<String,ObjectsingletonObjects = 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<PropertypropertyList = 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<PropertygetPropertyList() {
        return propertyList;
    }
    public void setPropertyList(List<PropertypropertyList) {
        this.propertyList = propertyList;
    }
}

定義Property



/**
 * 用于封裝一個(gè)property標(biāo)簽
 * 屬性數(shù)據(jù)
 * @作者 itcast
 * @創(chuàng)建日期 2020/7/8 15:44
 **/
public class Property {
    private String name// 屬性名稱
    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<Elementlist = 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<ElementpropertyList = 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中依賴的屬性列表

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

實(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,BeanDefinitionbeanDefinitionMap = new ConcurrentHashMap<>();
    // 提供 singletonObjects 存儲(chǔ)bean的對(duì)象實(shí)例 (scope為singleton的)
    private Map<String,ObjectsingletonObjects = 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中依賴的屬性列表
     * //實(shí)現(xiàn)屬性的依賴注入
     * 創(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());
        }
        // 依賴注入
        List<PropertypropertyList = 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,Stringparams = 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)依賴問(wèn)題

A 依賴 B B 依賴 A 產(chǎn)生閉環(huán),稱為循環(huán)依賴

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

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

比如一個(gè)類(lèi)A中有一個(gè)屬性是B類(lèi),B類(lèi)中有一個(gè)屬性是A類(lèi),這時(shí)看Spring是怎么解決他們的相互依賴的。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)依賴
singletonFactories 三級(jí)緩存 存放 bean 工廠對(duì)象,用于解決循環(huán)依賴


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

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

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



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覆蓋掉稱為bean的覆蓋,bean的覆蓋不會(huì)報(bào)錯(cuò),但可能影響我們的項(xiàng)目,可以通過(guò)屬性設(shè)置不允許bean的覆蓋,allowBeanDefinitionOverriding設(shè)置為false。


猜你喜歡:

什么是Shiro?Shiro有什么特點(diǎn)?

Shiro身份認(rèn)證流程

什么是系統(tǒng)授權(quán)?系統(tǒng)授權(quán)流程介紹

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

0 分享到:
和我們?cè)诰€交談!