• spring源码系列02DefaultListableBeanFactory的介绍和使用


    spring源码系列02-DefaultListableBeanFactory的介绍和使用

    通过上一篇文章,了解到ApplicationContext系列容器的内部会持有一个DefaultListableBeanFactory容器,bean都是放在这个容器里头的。

    它是BeanFactory的实现类。这一次就来探索下这个类,看看直接把这个类作为spring容器时如何使用。

    首先给出这个类的类图

    一、DefaultListableBeanFactory作为容器使用

    作为一个容器肯定是可以用来管理bean的,在使用ClassPathxmlApplicationContext时,我们需要指定一个配置文件,在其中给出bean的定义信息。最终容器启动时所有的bean都是放在内部的BeanFactory里边的。那么如何单独使用BeanFactory呢。

    1.1 如何描述Bean的定义信息

    有配置文件时,bean信息是在配置文件中配的,但实际上最终配置信息会被spring解析成接口BeanDefinition

    来描述Bean的定义信息。所以单独使用beanFactory时,我们需要以BeanDefinition的形式来给容器指定Bean定义信息。当然这是个接口,实际使用的是其实现类

    如下代码,使用RootBeanDefinition来描述了一个Bean

    BeanDefinition bd = new RootBeanDefinition(Person.class);
    

    1.2 如何给spring容器中指定bean定义

    现在我们已经通过BeanDefinition描述了bean的信息,那如何添加到spring容器中呢?

    观察上边的类图,DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,从名字就可以看出这个接口中的方法可以用来给spring容器中注册bean,其中有一个方法

    	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    			throws BeanDefinitionStoreException;
    

    这个方法就是用来给容器中注册bean的。

    1.3 创建并使用容器

    通过上边的分析我们已经可以描述一个bean了,接下来就真正使用下容器,可以分为这几个步骤:

    创建容器,创建bean定义信息,注册bean定义信息,使用bean对象

    public static void main(String[] args) {
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            BeanDefinition bd = new RootBeanDefinition(Person.class);
            beanFactory.registerBeanDefinition("person",bd);
            System.out.println(beanFactory.getBean(Person.class));
    }
    

    上边的代码,就完成了把DefaultListableBeanFactory作为容器,向其中注册bean信息,获取bean这一个过程。

    1.4 DefaultListableBeanFactory的懒加载

    如果使用ApplicationContext类型的容器,当容器启动完成后所有的bean就已经被创建好了,而使用BeanFactory类型的容器,容器启动完成后并不会主动创建bean,只有主动从容器中getBean时才会真正的去创建该类型的bean。这就是懒加载。

    验证: 可以给person类添加一个无参数的构造方法,在其中输出一句话,然后去掉上边的输出语句在运行,就会发现该构造方法并没有执行;加上输出语句后构造方法会执行。

    二、DefaultListableBeanFactory中bean定义信息是如何存储的

    上边完成了使用DefaultListableBeanFactory作为spring容器来管理bean,现在在思考一个问题,bean的定义信息在这个类中是如何存储的?

    我们从该类的registerBeanDefinition方法入手

    Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){
    ...
    操作 this.beanDefinitionMap
    }
    

    方法内容很多,但其实都是在操作this.beanDefinitionMap,所以bean的定义信息是放在这个类的这个成员中的。

    /** Map of bean definition objects, keyed by bean name. */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    

    上边是定义成员变量的地方,通过源码的注释也可以看出它的作用。

    三、DefaultListableBeanFactory中是如何存储单例bean的

    这里我们在延伸一下,把这个类作为spring容器时,创建好的bean是在哪里存储的?

    这里只考虑单例bean,平时这种类型的bean使用的是最多的。

    观察上边的类图,其中有一个类叫做DefaultSingletonBeanRegistry,这个类中有一个成员变量singletonObjects,它就是用来存放我们的单例bean的,所以它又被叫做单例池

    /** Cache of singleton objects: bean name to bean instance. */
    	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    

    可以通过在DefaultListableBeanFactory类中追踪getSingleton方法来定位到这个成员。这个方法是从DefaultSingletonBeanRegistry,中继承的。

    四、如何加载xml配置文件

    上边对beanFactory容器的使用,都是在手动注册bean信息,那么如何去读取配置文件呢,就像使用ClassPathxmlApplicationContext 一样,其实spring提供了一个XmlBeanDefinitionReader

    ClassPathxmlApplicationContext这个容器内部也是使用这个reader来读取bean信息的

    public static void main(String[] args) {
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
            reader.loadBeanDefinitions("applicationContext.xml");
            System.out.println(beanFactory.getBean(Person.class));
        }
    

    这样就可以直接从xml文件中读取bean定义信息,至于如何解析注解来读取bean信息我们后续章节在看。

  • 相关阅读:
    GridView实用示例源码附加导出Excel功能
    在做web项目时经常遇到新闻要上一篇,下一篇
    wpf是什么
    今天发的一些文章是早以前遇到一些小问题,园友别炮轰我哦
    Excel表中的数据导入到数据库中
    WPF指南之XAML概述
    sql 替换字段内的内容及出现的问题
    const 和readonly
    SQL2008报Script failed for Server 'xxxxxx.database.windows.net' (Microsoft.SqlServer.Smo)这样的错误
    新年新气象
  • 原文地址:https://www.cnblogs.com/chengxuxiaoyuan/p/16270369.html
Copyright © 2020-2023  润新知