zoukankan      html  css  js  c++  java
  • 【一步一步学习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
    class beanClassName
    scope scope
    lazy-init lazyInit
    constructor-arg ConstructorArgument
    property MutablePropertyValues
    factory-method factoryMethodName
    destroy-method AbstractBeanDefinition.destroyMethodName
    init-method AbstractBeanDefinition.initMethodName
    autowire AbstractBeanDefinition.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());
    

    堆栈信息:

    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层
  • 相关阅读:
    利用python设计PDF报告,jinja2,whtmltopdf,matplotlib,pandas
    RPC服务不可用总结
    每次打开VS都报错:我们无法自动填充你的 Visual Studio Team Services 帐户
    每天一个linux命令(28):tar命令
    每天一个linux命令(23):Linux 目录结构
    每天一个linux命令(13):less 命令
    jquery对cookie进行读取、写入和删除
    vscode常用快捷键总结
    浏览器报Mixed Content错误的解决
    React.Children的使用
  • 原文地址:https://www.cnblogs.com/xxxuwentao/p/9578518.html
Copyright © 2011-2022 走看看