BeanDefinition

BeanDefinition

上述Spring的基本运行中,你所有的定义描述信息都在XML文件里面,如何读取呢?
当然通过 new ClassPathXmlApplicationContext("applicationcontext.xml")
该代码就是读取XML文件,而Bean对象信息就在xml里面,Bean的定义信息通过XML读取到了IOC容器中,此时,IOC的容器出现了bean的定义信息,并赋予了一个名字:BeanDefinition

BeanDefinitionReader

BeanDefinitionReader :规范信息的接口
BeanDefinitionReader 的作用是读取 Spring 配置文件中的内容,将其转换为 IoC 容器内部的数据结构:BeanDefinition

  • BeanDefinitionRegistry 接口一次只能注册一个 BeanDefinition
  • 只能自己构造 BeanDefinition 类来注册
  • BeanDefinitionReader 解决了这些问题
    • BeanDefinitionReader 可以使用一个 BeanDefinitionRegistry 构造
    • 然后通过 loadBeanDefinitions()等方法,把 Resources 转化为多个 BeanDefinition 并注册到 BeanDefinitionRegistry
public interface BeanDefinitionReader {
    //返回Bean工厂以向其注册Bean定义。
    BeanDefinitionRegistry getRegistry();
 
    /**返回资源加载器以用于资源位置。可以检查ResourcePatternResolver接口并进行相应的转换,以针对给定的资源模式加载多个资源。一个null返回值表明,绝对资源加载不适用于这个bean定义阅读器。
    这主要用于从bean定义资源中导入其他资源,例如,通过XML bean定义中的“ import”标记。但是,建议相对于定义资源应用此类导入;只有明确的完整资源位置才会触发绝对资源加载。
    **/
    @Nullable
    ResourceLoader getResourceLoader();
 
    //返回用于Bean类的类加载器。
    @Nullable
    ClassLoader getBeanClassLoader();
 
    //返回BeanNameGenerator用于匿名Bean(未指定显式Bean名称)。
    BeanNameGenerator getBeanNameGenerator();
 
    //从指定的资源加载bean定义。
    int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;
 
    int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;
 
    //从指定的资源位置加载bean定义。
    //该位置也可以是位置模式,前提是此bean定义读取器的ResourceLoader是ResourcePatternResolver。
    int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;
 
    int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}

关于 BeanDefinitionReader 的结构图如下:

BeanDefinitionReader
AbstractBeanDefinitionReader
XmlBeanDefinitionReader
PropertiesBeanDefinitionReader
GroovyBeanDefinitionReader
AbstractBeanDefinitionReader

该类是实现了 BeanDefinitionReader 和 EnvironmentCapable 接口的抽象类,提供常见属性:

  • 工作的 bean 工厂、
  • 资源加载器、
  • 用于加载 bean 类的类加载器、
  • 环境等

在这里插入图片描述
子类如下:

  • XmlBeanDefinitionReader:读取 XML 文件定义的 BeanDefinition
  • PropertiesBeanDefinitionReader:可以从属性文件,Resource,Property 对象等读取 BeanDefinition
  • GroovyBeanDefinitionReader:可以读取 Groovy 语言定义的 Bean

关于该类最核心的方法是 loadBeanDefinitions()方法,所以接下来我们主要就是分析该方法
在这里插入图片描述
在这里插入图片描述
根据资源加载器的不同,来处理资源路径,从而返回多个或一个资源,然后再将资源作为参数传递给 loadBeanDefinitions(resources)方法。在该类中存在一个 loadBeanDefinitions(Resource… resources)方法,该方法用于处理多个资源,归根结底,最后还是调用 loadBeanDefinitions((Resource)resource)方法,该方法的具体实现在 XmlBeanDefinitionReader 中。

XmlBeanDefinitionReader

该类作为 AbstractBeanDefinitionReader 的扩展类,继承了 AbstractBeanDefinitionReader 所有的方法,同时也扩展了很多新的方法,主要用于读取 XML 文件中定义的 bean。
XmlBeanDefinitionReader ,将xml中定义的bean解析为BeanDefinition对像

xml配置如下:

 <bean id=? class=?>
  <property name=? value=?>
  <property name=? ref=?>
  </bean>
      
  <bean id=? class=?>
  <constructor-arg name=? value=?>
  <constructor-arg name=? ref=?>
  </bean>

具体使用如下:

public void getBeanDefinition(){
    ClassPathResource resource = new ClassPathResource("application_context.xml");
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(resource);
}

获取资源

  • 获取 BeanFactory
    • 根据新建的 BeanFactory 创建一个BeanDefinitionReader对象,该Reader 对象为资源的解析器

装载资源

  • 整个过程就分为三个步骤:
    • 资源定位
      • 我们一般用外部资源来定义 Bean 对象,所以在初始化 IoC 容器的第一步就是需要定位这个外部资源
    • 装载
      • 装载就是
        • BeanDefinition 的载入
        • BeanDefinitionReader 读取
        • 解析 Resource 资源
        • 也就是将用户定义的 Bean 表示成 IoC 容器 的内部数据结构:BeanDefinition\
        • 在 IoC 容器内部维护着一个 BeanDefinition Map 的数据结构,在配置文件中每一个都对应着一个 BeanDefinition 对象。
    • 注册
      • 向 IoC 容器注册在上一步解析好的 BeanDefinition,这个过程是通过 BeanDefinitionRegistry 接口来实现的
      • 本质上是将解析得到的 BeanDefinition 注入到一个 HashMap 容器中,IoC 容器就是通过这个HashMap 来维护这些 BeanDefinition 的
      • 注意:此过程并没有完成依赖注入,依赖注册是发生在应用第一次调用 getBean()向容器索要 Bean 时。当然我们可以通过设置预处理,即对某个 Bean 设置 lazyInit 属性

接着上述的 loadBeanDefinitions(),我们看一下在 XmlBeanDefinitionReader 类中的具体实现
在这里插入图片描述
loadBeanDefinitions(resource) 是加载资源的真正实现,

加载BeanDefinition
封装
ResourcesCurrentlyBeingLoaded.get
已经存在该资源
没有存在
指定的 XML文件
Resource
EncodedResource
获取已经加载过的资源
抛出BeanDefinitionStoreException异常
将encodedResource加入其中
从 encodedResource 获取封装的Resource资源并从 Resource 中获取相应的 InputStream
最后将 InputStream 封装为 InputSource 调用 doLoadBeanDefinitions方法

loadBeanDefinitions(resource) 是加载资源的真正实现
从指定的 XML 文件加载 Bean Definition,这里会对 Resource 封装成 EncodedResource,主要是为了对 Resource 进行编码,保证内容读取的正确性。封装成 EncodedResource 后,调用 loadBeanDefinitions(encodedResource)。

  1. 首先通过 resourcesCurrentlyBeingLoaded.get() 来获取已经加载过的资源,
  2. 然后将 encodedResource
  3. 如果 resourcesCurrentlyBeingLoaded 中已经存在该资源,则抛出 BeanDefinitionStoreException
  4. 完成后从 encodedResource 获取封装的 Resource 资源并从 Resource 中获取相应的 InputStream
  5. 最后将 InputStream 封装为 InputSource 调用 doLoadBeanDefinitions()

方法 doLoadBeanDefinitions() 为从 xml 文件中加载 Bean Definition 的真正逻辑

demo测试

  1. 实体类
package com.example.spring_01.entity;

import lombok.Data;

@Data
public class Person {
    private String name;
    private String  age;
}
  1. 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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.example.spring_01.entity.Person">
        <property name="name" value="sb"/>
        <property name="age" value="666"/>
    </bean>
</beans>

  1. 测试demo
 @Test
    public void demoTest() {
        //创建一个spring容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //定义一个xml方式的bean的读取器,需要传入一个bean的注册器
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);
        //根据xml文件的位置解析定义的bean,并将其注册到我们上面指定的spring容器中
        String location="bean.xml";
        xmlBeanDefinitionReader.loadBeanDefinitions(location);
        for (String beanName:factory.getBeanDefinitionNames()){
            System.out.println(beanName+"===>"+factory.getBean(beanName));
        }
    }
  1. 结果集
    在这里插入图片描述
  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值