• 设计模式(二十九)----综合应用-自定义Spring框架-Spring IOC相关接口分析


    1 BeanFactory解析

    Spring中Bean的创建是典型的工厂模式,这一系列的Bean工厂,即IoC容器,为开发者管理对象之间的依赖关系提供了很多便利和基础服务,在Spring中有许多IoC容器的实现供用户选择,其相互关系如下图所示。

    其中,BeanFactory作为最顶层的一个接口,定义了IoC容器的基本功能规范,BeanFactory有三个重要的子接口:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。但是从类图中我们可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。

    那么为何要定义这么多层次的接口呢?

    每个接口都有它的使用场合,主要是为了区分在Spring内部操作过程中对象的传递和转化,对对象的数据访问所做的限制。例如,

    • ListableBeanFactory接口表示这些Bean可列表化。

    • HierarchicalBeanFactory表示这些Bean 是有继承关系的,也就是每个 Bean 可能有父 Bean

    • AutowireCapableBeanFactory 接口定义Bean的自动装配规则。

    这三个接口共同定义了Bean的集合、Bean之间的关系及Bean行为。最基本的IoC容器接口是BeanFactory,来看一下它的源码:

    public interface BeanFactory {
    ​
        String FACTORY_BEAN_PREFIX = "&";
    ​
        //根据bean的名称获取IOC容器中的的bean对象
        Object getBean(String name) throws BeansException;
        //根据bean的名称获取IOC容器中的的bean对象,并指定获取到的bean对象的类型,这样我们使用时就不需要进行类型强转了
         T getBean(String name, Class requiredType) throws BeansException;
        Object getBean(String name, Object... args) throws BeansException;
         T getBean(Class requiredType) throws BeansException;
         T getBean(Class requiredType, Object... args) throws BeansException;
        
         ObjectProvider getBeanProvider(Class requiredType);
         ObjectProvider getBeanProvider(ResolvableType requiredType);
    ​
        //判断容器中是否包含指定名称的bean对象
        boolean containsBean(String name);
        //根据bean的名称判断是否是单例
        boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
        boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
        boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
        boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException;
        @Nullable
        Class getType(String name) throws NoSuchBeanDefinitionException;
        String[] getAliases(String name);
    }

    在BeanFactory里只对IoC容器的基本行为做了定义,根本不关心你的Bean是如何定义及怎样加载的。正如我们只关心能从工厂里得到什么产品,不关心工厂是怎么生产这些产品的。

    BeanFactory有一个很重要的子接口,就是ApplicationContext接口,该接口主要来规范容器中的bean对象是非延时加载,即在创建容器对象的时候就对象bean进行初始化,并存储到一个容器中。

    要知道工厂是如何产生对象的,我们需要看具体的IoC容器实现,Spring提供了许多IoC容器实现,比如:

    • ClasspathXmlApplicationContext : 根据类路径加载xml配置文件,并创建IOC容器对象。

    • FileSystemXmlApplicationContext :根据系统路径加载xml配置文件,并创建IOC容器对象。

    • AnnotationConfigApplicationContext :加载注解类配置,并创建IOC容器。

    2 BeanDefinition解析

    Spring IoC容器管理我们定义的各种Bean对象及其相互关系,而Bean对象在Spring实现中是以BeanDefinition来描述的,如下面配置文件

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
    ​
    bean标签还有很多属性:
        scope、init-method、destory-method等。

    其继承体系如下图所示。

    3 BeanDefinitionReader解析

    Bean的解析过程非常复杂,功能被分得很细,因为这里需要被扩展的地方很多,必须保证足够的灵活性,以应对可能的变化。Bean的解析主要就是对Spring配置文件的解析。这个解析过程主要通过BeanDefinitionReader来完成,看看Spring中BeanDefinitionReader的类结构图,如下图所示。

    看看BeanDefinitionReader接口定义的功能来理解它具体的作用:

    public interface BeanDefinitionReader {
    ​
        //获取BeanDefinitionRegistry注册器对象
        BeanDefinitionRegistry getRegistry();
    ​
        @Nullable
        ResourceLoader getResourceLoader();
    ​
        @Nullable
        ClassLoader getBeanClassLoader();
    ​
        BeanNameGenerator getBeanNameGenerator();
    ​
        /*
            下面的loadBeanDefinitions都是加载bean定义,从指定的资源中
        */
        int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
        int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
        int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
        int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
    }

    4 BeanDefinitionRegistry解析

    BeanDefinitionReader用来解析bean定义,并封装BeanDefinition对象,而我们定义的配置文件中定义了很多bean标签,所以就有一个问题,解析的BeanDefinition对象存储到哪儿?答案就是BeanDefinition的注册中心,而该注册中心顶层接口就是BeanDefinitionRegistry。

    public interface BeanDefinitionRegistry extends AliasRegistry {
    ​
        //往注册表中注册bean
        void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionStoreException;
    ​
        //从注册表中删除指定名称的bean
        void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    ​
        //获取注册表中指定名称的bean
        BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
        
        //判断注册表中是否已经注册了指定名称的bean
        boolean containsBeanDefinition(String beanName);
        
        //获取注册表中所有的bean的名称
        String[] getBeanDefinitionNames();
        
        int getBeanDefinitionCount();
        boolean isBeanNameInUse(String beanName);
    }

    继承结构图如下:

    从上面类图可以看到BeanDefinitionRegistry接口的子实现类主要有以下几个:

    • DefaultListableBeanFactory

      在该类中定义了如下代码,就是用来注册bean

      private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    • SimpleBeanDefinitionRegistry

      在该类中定义了如下代码,就是用来注册bean

      private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);

    5 创建容器

    ClassPathXmlApplicationContext对Bean配置资源的载入是从refresh()方法开始的。refresh()方法是一个模板方法,规定了 IoC 容器的启动流程,有些逻辑要交给其子类实现。它对 Bean 配置资源进行载入,ClassPathXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()方法启动整个IoC容器对Bean定义的载入过程。

     



    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    查看 SSH 登录失败日志
    如何使用XSSFWorkbook读取文本薄?
    乾元通4G/5G多链路聚合设备在公共安全通信方面解决方案
    「Python」面向对象封装案例1——小夏爱跑步、案例扩展
    上手python之字典
    计算机视觉——飞桨深度学习实战-图像分类算法原理与实战
    C语言之位段
    maven 多模块项目的测试覆盖率分析 - jacoco 聚合分析
    扯淡的DevOps,我们开发根本不想做运维!
    Linux环境修改服务器时间和网络时间保持一致
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/16563364.html