当前位置: 首页 > news >正文

【一步一步学习spring】【番外】IOC 设计原理与实现

2、Bean的构建过程

2.1 创建bean

spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖,研究透它的前生今世对我们理解spring ioc的概念有着重要的作用。

img

  • bean类
package com.demo;
class User {
    private UserDao userdao;
    
    public void say() {
        System.out.println("hello User.");
    }

    public UserDao getUserdao() {
        return userdao;
    }

    public void setUserdao(UserDao userdao) {
        this.userdao = userdao;
    }
}
  • 简单创建、存储、获取
package com.demo;

import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class BeanFactoryTest {
    @Test
    public void simpleBeanTest() {      
        DefaultListableBeanFactory fac = new DefaultListableBeanFactory();
        // 创建bean
        User user = fac.createBean(User.class);
        // 注册bean
        fac.registerSingleton("user", user);
        // 获取bean
        user = (User) fac.getBean("user");
        // 测试一下
        user.say();
    }
}
  • 存在依赖关系

有上面的User定义中可以看到,存在一个私有变量UserDao。

    @Test
    public void dependencyBeanTest() {
        DefaultListableBeanFactory fac = new DefaultListableBeanFactory();
        // 准备依赖的userdao
        UserDao userdao = fac.createBean(UserDao.class);
        fac.registerSingleton("userdao", userdao);
        // 创建bean,并依赖注入UserDao对象。
        User user = (User) fac.createBean(User.class, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
        // 注册bean
        fac.registerSingleton("user", user);
        // 获取bean
        user = (User) fac.getBean("user");
        // 测试一下
        user.say();
    }

2.2 bean的定义

BeanDefinition (Bean定义)
ioc 实现中 我们在xml 中描述的Bean信息最后 都将保存至BeanDefinition (定义)对象中,其中xml bean 与BeanDefinition 程一对一的关系。

由此可见,xml bean中设置的属性最后都会体现在BeanDefinition中。如:

XML-bean BeanDefinition
classbeanClassName
scopescope
lazy-initlazyInit
constructor-argConstructorArgument
propertyMutablePropertyValues
factory-methodfactoryMethodName
destroy-methodAbstractBeanDefinition.destroyMethodName
init-methodAbstractBeanDefinition.initMethodName
autowireAbstractBeanDefinition.autowireMode
id
name
  • [ ] 演示查看 BeanDefinition 属性结构

spring.xml 文件中保存了我们对Bean的描述配置,BeanFactory 会读取这些配置然后生成对应的Bean。这是我们对ioc原理的一般理解。但在深入一些我们会有更多的问题?

  1. 配置信息最后是谁JAVA中哪个对象承载的?
  2. 这些承载对象是谁读取XML文件并装载的?
  3. 这些承载对象又是保存在哪里?

BeanDefinitionRegistry(Bean注册器)
在上表中我们并没有看到 xml bean 中的 id 和name属性没有体现在定义中,原因是ID 其作为当前Bean的存储key注册到了BeanDefinitionRegistry 注册器中。name 作为别名key 注册到了 AliasRegistry 注册中心。其最后都是指向其对应的BeanDefinition。

  • [ ] 演示查看 BeanDefinitionRegistry属性结构

2.3 bean的加载

BeanDefinitionReader(Bean定义读取)

上图中可以看出Bean的定义是由BeanDefinitionReader 从xml 中读取配置并构建出 BeanDefinitionReader,然后在基于别名注册到BeanDefinitionRegister中。

  • [ ] 查看BeanDefinitionReader结构


方法说明:

  • loadBeanDefinitions(Resource resource)
    • 基于资源装载Bean定义并注册至注册器
  • int loadBeanDefinitions(String location)
    • 基于资源路径装载Bean定义并注册至注册器
  • BeanDefinitionRegistry getRegistry()
    • 获取注册器
  • ResourceLoader getResourceLoader()
    • 获取资源装载器
  • [ ] 基于示例演示BeanDefinitionReader装载过程
//创建一个简单注册器
BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
//创建bean定义读取器
BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
// 创建资源读取器
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
// 获取资源
Resource xmlResource = resourceLoader.getResource("spring.xml");
// 装载Bean的定义
reader.loadBeanDefinitions(xmlResource);
// 打印构建的Bean 名称
System.out.println(Arrays.toString(register.getBeanDefinitionNames());

堆栈信息:

625031-20180903145358875-2138221647.png

Beanfactory(bean 工厂)
有了Bean的定义就相当于有了产品的配方,接下来就是要把这个配方送到工厂进行生产了。在ioc当中Bean的构建是由BeanFactory 负责的。其结构如下:

方法说明:

  • getBean(String)
    • 基于ID或name 获取一个Bean
  • T getBean(Class requiredType)
    • 基于Bean的类别获取一个Bean(如果出现多个该类的实例,将会报错。但可以指定 primary=“true” 调整优先级来解决该错误 )
  • Object getBean(String name, Object... args)
    • 基于名称获取一个Bean,并覆盖默认的构造参数
  • boolean isTypeMatch(String name, Class<?> typeToMatch)
    • 指定Bean与指定Class 是否匹配

以上方法中重点要关注getBean,当用户调用getBean的时候就会触发 Bean的创建动作,其是如何创建的呢?

堆栈信息:

#创建Bean堆栈
// 其反射实例化Bean
java.lang.reflect.Constructor.newInstance(Unknown Source:-1)
BeanUtils.instantiateClass()
//基于实例化策略 实例化Bean。也可以使用cglib的方式进行创建
SimpleInstantiationStrategy.instantiate()
AbstractAutowireCapableBeanFactory.instantiateBean()
// 执行Bean的实例化方法
AbstractAutowireCapableBeanFactory.createBeanInstance()
AbstractAutowireCapableBeanFactory.doCreateBean()
// 执行Bean的创建
AbstractAutowireCapableBeanFactory.createBean()
// 缓存中没有,调用指定Bean工厂创建Bean
AbstractBeanFactory$1.getObject()
// 从单例注册中心获取Bean缓存
DefaultSingletonBeanRegistry.getSingleton()
AbstractBeanFactory.doGetBean()
// 获取Bean
AbstractBeanFactory.getBean()
// 调用的客户类
com.spring.BeanFactoryExample.main()

Bean创建时序图:

从调用过程可以总结出以下几点:

  1. 调用BeanFactory.getBean() 会触发Bean的实例化。
  2. DefaultSingletonBeanRegistry 中缓存了单例Bean。
  3. Bean的创建与初始化是由AbstractAutowireCapableBeanFactory 完成的。

    3、BeanFactory 与 ApplicationContext区别

    BeanFactory 看下去可以去做IOC当中的大部分事情,为什么还要去定义一个ApplicationContext 呢?
    ApplicationContext 结构图

从图中可以看到 ApplicationContext 它由BeanFactory接口派生而来,因而提供了BeanFactory所有的功能。除此之外context包还提供了以下的功能:

  1. MessageSource, 提供国际化的消息访问
  2. 资源访问,如URL和文件
  3. 事件传播,实现了ApplicationListener接口的bean
  4. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

转载于:https://www.cnblogs.com/xxxuwentao/p/9578518.html

相关文章:

  • Python 面向对象 2
  • 1344 线型网络
  • 关于mysql严格模式的开启、关闭
  • Jenkins自动化CI CD流水线之5--pipeline
  • 在博客园写了一年博客,收获的不仅仅是写作技能——我能一直保持积极的学习和工作态度...
  • luogu1556 幸福的路
  • Win10安装MySQL5.7.22 解压缩版(手动配置)方法
  • Java将图片转换成Base64字符串
  • MyBatis原理-拦截器
  • Django项目 第一课 【nvm、node、npm安装及使用】
  • 牛客网暑期ACM多校训练营(第三场) H Diff-prime Pairs(欧拉筛法)
  • CF 1036 B Diagonal Walking v.2 —— 思路
  • 系统完整性检查工具--Tripwire和AIDE
  • tp5 路由定义
  • 随机图片
  • ----------
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • [译] 怎样写一个基础的编译器
  • exif信息对照
  • linux学习笔记
  • NSTimer学习笔记
  • Python学习之路13-记分
  • Sublime Text 2/3 绑定Eclipse快捷键
  • 从PHP迁移至Golang - 基础篇
  • 排序(1):冒泡排序
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 思考 CSS 架构
  • 移动端 h5开发相关内容总结(三)
  • (007)XHTML文档之标题——h1~h6
  • (2.2w字)前端单元测试之Jest详解篇
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (3)选择元素——(17)练习(Exercises)
  • (AngularJS)Angular 控制器之间通信初探
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (pytorch进阶之路)扩散概率模型
  • (力扣)1314.矩阵区域和
  • (强烈推荐)移动端音视频从零到上手(上)
  • (五)IO流之ByteArrayInput/OutputStream
  • (学习日记)2024.01.19
  • (转)Unity3DUnity3D在android下调试
  • *** 2003
  • .NET Framework 服务实现监控可观测性最佳实践
  • .NET 常见的偏门问题
  • .NET 中的轻量级线程安全
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET基础篇——反射的奥妙
  • .net实现头像缩放截取功能 -----转载自accp教程网
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • [2016.7.test1] T2 偷天换日 [codevs 1163 访问艺术馆(类似)]
  • [2017][note]基于空间交叉相位调制的两个连续波在few layer铋Bi中的全光switch——
  • [AutoSar]状态管理(五)Dcm与BswM、EcuM的复位实现